2016-01-11 19 views
8

ストリーミングビデオリストアプリを実装したいと思います。私はリストアイテムを表示するのにRecyclerViewを使用しました。アイテムタイプには、記事、ステータス、写真、ビデオの4種類があります。私たちはビデオタイプだけに焦点を当てるべきです。Exoplayerを使用したスト​​リーミングビデオリスト

public class FollowedPostAdapter extends RecyclerView.Adapter implements OnFollowTagCallback, OnLikeCallback { 
    private Context context; 
    private List<PostItem> newsFeedList; 
    public RecyclerView recyclerView; 
    public LinearLayoutManager linearLayoutManager; 
    private HashMap<Integer, DemoPlayer> playerList; 

    private int visibleThreshold = 5; 
    // private int previousTotal = 0; 
    private int visibleItemCount, firstVisibleItem, totalItemCount; 
    private boolean loading; 
    private OnRecyclerViewLoadMoreListener loadMoreListener; 


    private final String text_comment; 
    private final String mReadMoreHtml; 
    private long userId; 


    public FollowedPostAdapter(Context context, RecyclerView recyclerView, List<PostItem> newsFeedList) { 
     this.context = context; 
     playerList = new HashMap<>(); 
     this.newsFeedList = newsFeedList; 
     this.recyclerView = recyclerView; 
     this.linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); 

    } 

    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     RecyclerView.ViewHolder viewHolder; 
     if (viewType == Constants.VIEWTYPE_ARTICLE) { 
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_followed_article_item, parent, false); 
      viewHolder = new ArticleViewHolder(view); 
     } else if (viewType == Constants.VIEWTYPE_STATUS) { 
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_followed_status_item, parent, false); 
      viewHolder = new StatusViewHolder(view); 
     } else if (viewType == Constants.VIEWTYPE_PHOTO) { 
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_followed_photo_item, parent, false); 
      viewHolder = new PhotoViewHolder(view); 
     } else if (viewType == Constants.VIEWTYPE_VIDEO) { 
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_followed_video_item, parent, false); 
      viewHolder = new VideoViewHolder(view); 
     } else { 
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false); 
      viewHolder = new ProgressBarViewHolder(view); 
     } 
     return viewHolder; 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
     if (holder instanceof ArticleViewHolder) { 
      // code 

     } else if (holder instanceof StatusViewHolder) { 
     // code 

     } else if (holder instanceof PhotoViewHolder) { 
     // code 
     } else if (holder instanceof VideoViewHolder) { 
      PostItem item = newsFeedList.get(position); 
      VideoViewHolder mHolder = (VideoViewHolder) holder; 
      LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mHolder.videoView.getLayoutParams(); 
      lp.height = (int) (ScreenHelper.getScreenWidth((Activity) context) * Constants.POST_IMAGE_RATIO); 
      mHolder.videoView.setLayoutParams(lp); 
      mHolder.setup(item); 
      Picasso.with(context).load(item.imageCover).error(R.drawable.ic_user_avatar).placeholder(R.drawable.ic_user_avatar).into(mHolder.iv_avatar); 
      if (item.tags != null && item.tags.size() > 0) { 
       // get first tag as main tag 
       generateTagViews(mHolder.tag_flow_layout, item.tags.subList(0, 1), position); 
       mHolder.tag_flow_layout.setVisibility(View.VISIBLE); 
       mHolder.tag_flow_layout.setVisibility(View.VISIBLE); 
       // mHolder.indicator.setVisibility(View.VISIBLE); 
      } else { 
       mHolder.tag_flow_layout.setVisibility(View.GONE); 
       // mHolder.indicator.setVisibility(View.GONE); 
      } 
      if (item.time_created != null) { 
       mHolder.tv_time.setText(item.time_created); 
       //mHolder.indicator.setVisibility(View.VISIBLE); 
       mHolder.tv_time.setVisibility(View.VISIBLE); 
      } else { 
       //mHolder.indicator.setVisibility(View.GONE); 
       mHolder.tv_time.setVisibility(View.GONE); 
      } 
      if (item.description_short.isEmpty()) 
       mHolder.tv_description.setVisibility(View.GONE); 
      else { 
       mHolder.tv_description.setText(item.description_short); 
       mHolder.tv_description.setVisibility(View.VISIBLE); 
      } 

      mHolder.btn_comment.setText(String.valueOf(item.count_comment)); 
      mHolder.btn_like.setText(String.valueOf(item.count_like)); 
      mHolder.btn_unlike.setText(String.valueOf(item.count_unlike)); 
      mHolder.btn_share.setText(String.valueOf(item.count_share)); 
      if (item.tags.size() != 0) { 
       int tagId = item.tags.get(0).tag_id; 
       setFollowButtonActive(mHolder.btn_follow, TagHelper.isTagFollowed(tagId)); 
      } else 
       setFollowButtonActive(mHolder.btn_follow, false); 

     } 

    } 

    @Override 
    public void onViewRecycled(RecyclerView.ViewHolder holder) { 
     super.onViewRecycled(holder); 
     if (holder instanceof VideoViewHolder) { 
      DemoPlayer player = playerList.get(holder.getAdapterPosition()); 
      if (player != null) { 
       player.release(); 
       playerList.remove(holder.getAdapterPosition()); 
      } 
     } 
    } 


    public void pauseAllPlayers() { 
     for (int i = 0; i <= newsFeedList.size(); i++) { 
      DemoPlayer player = playerList.get(i); 
      if (player != null) { 
       if (player.getPlayerControl().isPlaying()) 
        player.getPlayerControl().pause(); 
       RecyclerView.ViewHolder holder = recyclerView.findViewHolderForLayoutPosition(i); 
       if (holder != null && holder instanceof VideoViewHolder) { 
        ((VideoViewHolder) holder).btn_play.setVisibility(View.VISIBLE); 
       } 

      } 
     } 
    } 





    public void refreshData() { 
     notifyDataSetChanged(); 
    } 

    public class ArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 
     // 
    } 

    public class StatusViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 

     // code 
    } 

    public class PhotoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 
     // code 
    } 

    public class VideoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, SurfaceHolder.Callback, AudioCapabilitiesReceiver.Listener, DemoPlayer.Listener, DemoPlayer.CaptionListener, DemoPlayer.Id3MetadataListener { 
     @Bind(R.id.iv_avatar) 
     ImageView iv_avatar; 
     @Bind(R.id.tag_flow_layout) 
     FlowLayout tag_flow_layout; 
     @Bind(R.id.tv_time) 
     TextView tv_time; 
     @Bind(R.id.btn_follow) 
     FancyButton btn_follow; 
     @Bind(R.id.btn_comment) 
     FancyButton btn_comment; 
     @Bind(R.id.btn_like) 
     FancyButton btn_like; 
     @Bind(R.id.btn_unlike) 
     FancyButton btn_unlike; 
     @Bind(R.id.btn_share) 
     FancyButton btn_share; 
     @Bind(R.id.root) 
     FrameLayout videoView; 
     @Bind(R.id.btn_play) 
     ImageView btn_play; 
     @Bind(R.id.tv_description) 
     TextView tv_description; 

     // player's variable 
     private EventLogger eventLogger; 

     // private VideoControllerView mediaController; 
     private View shutterView; 
     private AspectRatioFrameLayout videoFrame; 
     private SurfaceView surfaceView; 
     private SubtitleLayout subtitleLayout; 

     private DemoPlayer player; 
     private boolean playerNeedsPrepare; 

     private long playerPosition = 0; 

     private Uri contentUri; 
     private int contentType; 
     private String contentId; 

     public static final int TYPE_DASH = 0; 
     public static final int TYPE_SS = 1; 
     public static final int TYPE_HLS = 2; 
     public static final int TYPE_OTHER = 3; 

     private static final String EXT_DASH = ".mpd"; 
     private static final String EXT_SS = ".ism"; 
     private static final String EXT_HLS = ".m3u8"; 

     private AudioCapabilitiesReceiver audioCapabilitiesReceiver; 

     public VideoViewHolder(View view) { 
      super(view); 
      ButterKnife.bind(this, view); 
      iv_avatar.setOnClickListener(this); 
      btn_follow.setOnClickListener(this); 
      btn_comment.setOnClickListener(this); 
      btn_like.setOnClickListener(this); 
      btn_unlike.setOnClickListener(this); 
      btn_share.setOnClickListener(this); 

      // player's setup 
      View root = view.findViewById(R.id.root); 
      root.setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View v) { 
        doPlayResume(); 
       } 
      }); 
//   root.setOnTouchListener(new View.OnTouchListener() { 
//    @Override 
//    public boolean onTouch(View view, MotionEvent motionEvent) { 
//     if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 
//      toggleControlsVisibility(); 
//     } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { 
//      view.performClick(); 
//     } 
//     return true; 
//    } 
//   }); 
//   root.setOnKeyListener(new View.OnKeyListener() { 
//    @Override 
//    public boolean onKey(View v, int keyCode, KeyEvent event) { 
//     if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE 
//       || keyCode == KeyEvent.KEYCODE_MENU) { 
//      return false; 
//     } 
//     return mediaController.dispatchKeyEvent(event); 
//    } 
//   }); 
      shutterView = view.findViewById(R.id.shutter); 
      videoFrame = (AspectRatioFrameLayout) view.findViewById(R.id.video_frame); 
      surfaceView = (SurfaceView) view.findViewById(R.id.surface_view); 
      surfaceView.getHolder().addCallback(this); 
      subtitleLayout = (SubtitleLayout) view.findViewById(R.id.subtitles); 
//   mediaController = new VideoControllerView(context); 
//   mediaController.setAnchorView((ViewGroup) root); 
      audioCapabilitiesReceiver = new AudioCapabilitiesReceiver(context, this); 
      audioCapabilitiesReceiver.register(); 
     } 

     @Override 
     public void onClick(View v) { 
      switch (v.getId()) { 
       case R.id.iv_avatar: 
        viewTagDetail(getAdapterPosition()); 
        break; 
       case R.id.btn_follow: 
        followTag((FancyButton) v, getAdapterPosition()); 
        break; 
       case R.id.btn_comment: 
        commentPost(getAdapterPosition()); 
        break; 
       case R.id.btn_like: 
        likePost(getAdapterPosition(), btn_like, btn_unlike); 
        break; 
       case R.id.btn_unlike: 
        unlikePost(getAdapterPosition(), btn_like, btn_unlike); 
        break; 
       case R.id.btn_share: 
        sharePost(getAdapterPosition()); 
        break; 
       case R.id.btn_play: 
        doPlayResume(); 
        break; 
      } 
     } 

     public void setup(PostItem item) { 
      releasePlayer(); 
      player = playerList.get(getAdapterPosition()); 
      contentUri = Uri.parse(item.link); 
      contentType = TYPE_OTHER; 
      contentId = String.valueOf(item.post_id); 
      configureSubtitleView(); 
      if (player == null) { 
       preparePlayer(false); 
      } else { 
       player.setBackgrounded(false); 
      } 
     } 

     //  public void saveCurrentPosition() { 
//   if (player != null) 
//    videoItemList.get(getAdapterPosition()).position = player.getCurrentPosition(); 
//  } 
     public void doPlayResume() { 
      if (player == null) { 
       return; 
      } 

      if (player.getPlayerControl().isPlaying()) { 
       player.getPlayerControl().pause(); 
      } else { 
       player.getPlayerControl().start(); 
      } 
      showControls(); 
     } 

     @Override 
     public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) { 
      if (player == null) { 
       return; 
      } 
      boolean backgrounded = player.getBackgrounded(); 
      boolean playWhenReady = player.getPlayWhenReady(); 
      releasePlayer(); 
      preparePlayer(playWhenReady); 
      player.setBackgrounded(backgrounded); 
     } 

     private DemoPlayer.RendererBuilder getRendererBuilder() { 
      String userAgent = Util.getUserAgent(context, "ExoPlayerDemo"); 
      switch (contentType) { 
       case TYPE_SS: 
        return new SmoothStreamingRendererBuilder(context, userAgent, contentUri.toString(), 
          new SmoothStreamingTestMediaDrmCallback()); 
       case TYPE_DASH: 
        return new DashRendererBuilder(context, userAgent, contentUri.toString(), 
          new WidevineTestMediaDrmCallback(contentId)); 
       case TYPE_HLS: 
        return new HlsRendererBuilder(context, userAgent, contentUri.toString()); 
       case TYPE_OTHER: 
        return new ExtractorRendererBuilder(context, userAgent, contentUri); 
       default: 
        throw new IllegalStateException("Unsupported type: " + contentType); 
      } 
     } 

     private void preparePlayer(boolean playWhenReady) { 
      if (player == null) { 
       player = new DemoPlayer(getRendererBuilder()); 
       playerList.put(getAdapterPosition(), player); 
       player.addListener(this); 
       player.setCaptionListener(this); 
       player.setMetadataListener(this); 
       player.seekTo(playerPosition); 
       playerNeedsPrepare = true; 
//    mediaController.setMediaPlayer(player.getPlayerControl()); 
//    mediaController.setEnabled(true); 
       eventLogger = new EventLogger(); 
       eventLogger.startSession(); 
       player.addListener(eventLogger); 
       player.setInfoListener(eventLogger); 
       player.setInternalErrorListener(eventLogger); 
      } 
      if (playerNeedsPrepare) { 
       player.prepare(); 
       playerNeedsPrepare = false; 
      } 
      player.setSurface(surfaceView.getHolder().getSurface()); 
      player.setPlayWhenReady(playWhenReady); 
     } 

     private void releasePlayer() { 
      if (player != null) { 
       player.release(); 
       player = null; 
       eventLogger.endSession(); 
       eventLogger = null; 
       btn_play.setVisibility(View.VISIBLE); 
      } 
     } 

     @Override 
     public void onStateChanged(boolean playWhenReady, int playbackState) { 
      if (playbackState == ExoPlayer.STATE_ENDED) { 
       showControls(); 
      } 

     } 

     @Override 
     public void onError(Exception e) { 
      if (e instanceof UnsupportedDrmException) { 
       // Special case DRM failures. 
       UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e; 
       int stringId = Util.SDK_INT < 18 ? R.string.drm_error_not_supported 
         : unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME 
         ? R.string.drm_error_unsupported_scheme : R.string.drm_error_unknown; 
       Toast.makeText(context, stringId, Toast.LENGTH_LONG).show(); 
      } 
      playerNeedsPrepare = true; 
      showControls(); 
     } 

     @Override 
     public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { 
      shutterView.setVisibility(View.GONE); 
      videoFrame.setAspectRatio(
        height == 0 ? 1 : (width * pixelWidthHeightRatio)/height); 
     } 

     private boolean haveTracks(int type) { 
      return player != null && player.getTrackCount(type) > 0; 
     } 

//  private void toggleControlsVisibility() { 
//   if (mediaController.isShowing()) { 
//    mediaController.hide(); 
//   } else { 
//    showControls(); 
//   } 
//  } 

     private void showControls() { 
//   mediaController.show(5000); 
      if (player.getPlayerControl().isPlaying()) 
       btn_play.setVisibility(View.GONE); 
      else 
       btn_play.setVisibility(View.VISIBLE); 

     } 

     @Override 
     public void onCues(List<Cue> cues) { 
      subtitleLayout.setCues(cues); 
     } 

     @Override 
     public void onId3Metadata(Map<String, Object> metadata) { 

     } 

     @Override 
     public void surfaceCreated(SurfaceHolder holder) { 
      if (player != null) { 
       player.setSurface(holder.getSurface()); 
      } 
     } 

     @Override 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     } 

     @Override 
     public void surfaceDestroyed(SurfaceHolder holder) { 
      if (player != null) { 
       holder.lockCanvas(); 
       player.blockingClearSurface(); 
      } 
     } 

     private void configureSubtitleView() { 
      CaptionStyleCompat style; 
      float fontScale; 
      if (Util.SDK_INT >= 19) { 
       style = getUserCaptionStyleV19(); 
       fontScale = getUserCaptionFontScaleV19(); 
      } else { 
       style = CaptionStyleCompat.DEFAULT; 
       fontScale = 1.0f; 
      } 
      subtitleLayout.setStyle(style); 
      subtitleLayout.setFractionalTextSize(SubtitleLayout.DEFAULT_TEXT_SIZE_FRACTION * fontScale); 
     } 

     @TargetApi(19) 
     private float getUserCaptionFontScaleV19() { 
      CaptioningManager captioningManager = 
        (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); 
      return captioningManager.getFontScale(); 
     } 

     @TargetApi(19) 
     private CaptionStyleCompat getUserCaptionStyleV19() { 
      CaptioningManager captioningManager = 
        (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); 
      return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle()); 
     } 

     private int inferContentType(Uri uri, String fileExtension) { 
      String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension 
        : uri.getLastPathSegment(); 
      if (lastPathSegment == null) { 
       return TYPE_OTHER; 
      } else if (lastPathSegment.endsWith(EXT_DASH)) { 
       return TYPE_DASH; 
      } else if (lastPathSegment.endsWith(EXT_SS)) { 
       return TYPE_SS; 
      } else if (lastPathSegment.endsWith(EXT_HLS)) { 
       return TYPE_HLS; 
      } else { 
       return TYPE_OTHER; 
      } 
     } 
    } 

    public class ProgressBarViewHolder extends RecyclerView.ViewHolder { 
     public ProgressBarViewHolder(View view) { 
      super(view); 
     } 
    } 

    public void unregisterEventBus() { 
     EventBus.getDefault().unregister(this); 
    } 
} 
  • 項目タイプがビデオであるとき、私はこのビデオを再生し、キー値を持つ(後で使用するためHashMapに、このインスタンスを追加するExoPlayerインスタンスを作成するには、アイテムの次のとおりです。ここでRecyclerViewのアダプターのための私のコードですポジション)。動画アイテムがリサイクルされている場合は、プレーヤーを解放してHashMapから削除します。

  • すべてうまく見えますが問題です。私は、ビデオアイテムが0の位置にあると仮定します(今私たちはこのアイテムのビデオプレビューを見ることができます)。 RecyclerViewをスクロールして項目0を非表示にするだけです。この時点で、項目0のVideoViewHolderはまだリサイクルされていません。次に、項目0を表示するようにスクロールします。ビューは空になり、ビデオプレビューは表示されません。アイテム0をクリックしてビデオを再生すると、プレーヤーはオーディオ(サウンド)のみを再生し、ビデオは表示しません。数秒間再生すると、ビデオが表示されます。

  • ビデオアイテムを非表示にするためにスクロールした後に、SurfaceViewが破棄されました。上にスクロールしてビデオアイテムを表示すると、SurfaceViewが作成されます。これが、ビデオプレビューの代わりに、VideoViewHolderに空白の表示が表示される理由だと思います。

  • ここに私の質問です:ビデオアイテムにスクロールした後にビデオプレビューを表示するには?ここで

+0

の下に表示のようなあなたのxmlファイルで設定する必要があり、あなたはどんな解決策を見つけますか?!私はこの問題を抱えている – Hani

答えて

0

SurfaceViewのレンダリングが正しく以前のリリースでAndroid N.までビューのアニメーションと同期していなかったExoPlayer documentationからノート

SurfaceViewは、コンテナをスクロール中に入れたとき、これは望ましくない影響をもたらす可能性があります、またはアニメーションを受けたときに発生します。このようなエフェクトには、SurfaceViewのコンテンツが表示されるべき場所より少し遅れて表示され、アニメーションの対象となったときに黒く表示されるビューが含まれていました。

Android Nより前の動画をスムーズにアニメーションまたはスクロールするには、SurfaceViewではなくTextureViewを使用する必要があります。滑らかなアニメーションやスクロールが必要とされていない場合は、SurfaceViewはTextureView surface_typeを有効にするには

を優先する必要がありますが

<com.google.android.exoplayer2.ui.SimpleExoPlayerView 
    android:id="@+id/playerView" 
    android:layout_width="match_parent" 
    android:layout_height="200dp" 
    app:surface_type="texture_view"/> 
関連する問題