简书链接:androidrecyclerview列表播放视频视频全屏翻页自动播放高仿微视之路  文章字数:1154,阅读全文大约需要4分钟 我这文章暂时是打广告的,要使用列表播放的朋友
http://github.com/qssq/videoplayer  视频效果http://www.iqiyi.com/w_19rxx2xtg5.html 
要做2件事情,第一 要监听recyclerview的滚动状态变为空闲的时候寻找videoview 进行播放
第二 ,要再recyclerview的布局改变的时候也寻找videoview进行播放
第三 让视频无缝无白屏闪屏播放
所以我就不用国内的这些第三方了,感觉摸不着头脑,y因为搞不到为何findview之后调用播放按钮竟然毛线反应没有,
于是找到了一个国外的,但是有很多坑 我修改了好几天,解决了白闪问题,增加了缓冲的显示,增加了点击播放暂停的控制
使用方法
1 compile 'cn.qssq666:video-player-manager:0.5' 
 
如果多个界面都有列表视频播放 mVideoPlayerManager 那么在界面不可见的时候各位要进行暂停或者销毁 创建单例管理器
fragment或activity的处理 构建管理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 mVideoPlayerManager = new SingleVideoPlayerManager(new PlayerItemChangeListener() {          @Override          public void onPlayerItemChanged(MetaData metaData) {          }      }      ) {          @Override          public void onVideoPlayTimeChanged(int positionInMilliseconds) {              float duration = mVideoPlayerManager.getCurrentPlayer().getDuration();              int percent = (int) (positionInMilliseconds / duration * 100f); //   int shouldSetWidth = (int) ((getWidth() / (float) mMaxProgress) * progress);              if (BuildConfig.DEBUG) {                  if (binding != null) {                      binding.progressBar.setProgress(percent);                  }                  Log.w(TAG, "percent:" + percent);              }          }          @Override          public void onPrepare() {              binding.progressBar.setProgress(0);          }      }; 
 
监听recyclerview的滚动 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22    binding.viewpager.addOnScrollListener(new RecyclerView.OnScrollListener() {             @Override             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                 int actualCurrentPosition = 0;                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {                     //第一次没法解决                        autoPlayVideo(binding.viewpager);//每次滚动一页就自动播放                 }             }         }); //解决第一次打开界面不播放问题         binding.viewpager.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {             @Override             public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {                 autoPlayVideo(binding.viewpager);                 Log.w(TAG,"V"+left+",top:"+top+",right:"+right+",bottom:"+bottom+",oldLeft:"+oldLeft+",oldTop:"+oldTop+",oldRight:"+oldRight);             }         }); 
 
自动播放的具体逻辑 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private void autoPlayVideo(RecyclerView view) {     RecyclerView.LayoutManager layoutManager = view.getLayoutManager();     int actualCurrentPosition = binding.viewpager.getCurrentPosition();     MetaData metaData = new MetaData() {     };     GenericDataBindViewHolder<ViewItemSmallVideoBinding> holder = (GenericDataBindViewHolder<ViewItemSmallVideoBinding>) binding.viewpager.findViewHolderForLayoutPosition(actualCurrentPosition);     if (holder == null) {         Log.e(TAG,"找不到viewholder");         return;     }     SmallVideoModel model1 = getAdapter().getData().get(actualCurrentPosition);     if (mVideoPlayerManager.isCurrent(model1.getVideo())) {         if(BuildConfig.DEBUG){             Log.w(TAG,"是当前视频,忽略");         }         return;     }     holder.getBinding().progressbar.setProgress(0);//     holder.getBinding().progressWrap.setVisibility(View.VISIBLE);     holder.getBinding().btnStart.setVisibility(View.GONE);     SmallVideoModel model = getAdapter().getData().get(actualCurrentPosition);     mVideoPlayerManager.playNewVideo(metaData, holder.getBinding().videoPlayer2, model.getVideo()); } 
 
页面声明周期控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Override public void onDestroy() {     super.onDestroy();     if (mVideoPlayerManager != null) {         mVideoPlayerManager.stopAnyPlayback();     } } @Override public void onResume() {     super.onResume();     if (mFromActivity) {         return;     }     Log.w(TAG, "PLAYSTEATE:" + mVideoPlayerManager.getCurrentPlayerState());     mVideoPlayerManager.continuePlay(); } @Override public void onPause() {     super.onPause();     if (mFromActivity) {         return;     }     Log.w(TAG, "PLAYSTEATE:" + mVideoPlayerManager.getCurrentPlayerState());     mVideoPlayerManager.pause(); } 
 
列表适配器的处理 视频列表view布局 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto">     <data>         <variable             name="model"             type="cn.qssq666.bean.SmallVideoModel" />     </data>     <FrameLayout         android:id="@+id/video_player_root"         android:layout_width="match_parent"         android:layout_height="match_parent">         <!--        <cn.jzvd.JZVideoPlayerStandard                     android:id="@+id/videoplayer"                     android:layout_width="match_parent"                     android:layout_height="20dp" />-->         <cn.qssq666.videomanager.ui.VideoPlayerView             android:id="@+id/video_player_2"             android:layout_width="match_parent"             android:layout_height="match_parent" />         <ImageView             android:id="@+id/iv"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:focusable="false"             android:focusableInTouchMode="false"             android:scaleType="centerCrop"             app:image="@{model.image}" />         <View             android:id="@+id/video_player_mask"             android:layout_width="match_parent"             android:layout_height="match_parent" />         <LinearLayout             android:layout_width="wrap_content"             android:layout_height="wrap_content">         </LinearLayout>         <LinearLayout             android:id="@+id/progress_wrap"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:layout_gravity="center"             android:gravity="center"             android:orientation="vertical"             android:visibility="gone">         <!-- 缓冲进度      -->             <ProgressBar                 android:id="@+id/progressbar"                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:layout_gravity="center"                 android:indeterminateTint="@color/theme_color_red"                 android:progress="50" />             <TextView                 android:id="@+id/progress_text"                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:layout_marginTop="5dp"                 android:text="0%"                 android:textColor="@color/theme_color_red"                 android:textSize="15sp" />         </LinearLayout>         <ImageView             android:id="@+id/btn_start"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:layout_gravity="center"             android:src="@drawable/video_big_btn_paly" />     </FrameLayout> </layout> 
 
监听视频透明封面的点击 请注意,这里播放视频是用管理器去操作播放,而不是通过布局的videoPlayer2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 View.OnClickListener l = new View.OnClickListener() {     @Override     public void onClick(View v) {         if (mVideoPlayerManager.isCurrent(model.getVideo())) {             if (mVideoPlayerManager.isPause()) {                 mVideoPlayerManager.continuePlay();             } else if (mVideoPlayerManager.isPlay()) {                 mVideoPlayerManager.pause();             } else {                 mVideoPlayerManager.playNewVideo(model, binding.videoPlayer2, model.getVideo());             }         } else {             binding.btnStart.setVisibility(View.GONE);  binding.progressWrap.setVisibility(View.VISIBLE);binding.progressText.setText("0%");             mVideoPlayerManager.playNewVideo(model, binding.videoPlayer2, model.getVideo());         }     } }; binding.videoPlayerMask.setOnClickListener(l); 
 
添加监听 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95         binding.videoPlayer2.addMediaPlayerListener(new MediaPlayerWrapper.MainThreadMediaPlayerListener() {             @Override             public void onVideoSizeChangedMainThread(int width, int height) {             }             @Override             public void onVideoPreparedMainThread() {             }             //作废             @Override             public void onProgressUpdate(int percent) { //                binding.seekbar.setProgress();             }             @Override             public void onVideoCompletionMainThread() {                 binding.videoPlayer2.restart();//播放完毕重新开始             }             @Override             public void onErrorMainThread(int what, int extra) {                 binding.progressWrap.setVisibility(View.GONE);                 binding.btnStart.setVisibility(View.VISIBLE);//这里少写了一个,应该让封面也显示出来             }             @Override             public void onBufferingUpdateMainThread(int percent) {                 if (percent == 100) {                     if (binding.progressWrap.getVisibility() == View.VISIBLE) {                         binding.progressWrap.setVisibility(View.GONE);                     }                 } else {                     if (binding.progressWrap.getVisibility() == View.GONE) {                         binding.progressWrap.setVisibility(View.VISIBLE);                     }                     binding.progressbar.setProgress(percent);                     binding.progressText.setText("" + percent + "%");                 }             }             @Override             public void onVideoStoppedMainThread() {                 // Show the cover when video stopped                 binding.iv.setVisibility(View.VISIBLE);                 binding.btnStart.setVisibility(View.VISIBLE);                 binding.progressWrap.setVisibility(View.GONE);             }             @Override             public void onPrepared(MediaPlayer mp) { //                binding.ivStart.setVisibility(View.g);             }             @Override             public void onPrepare() {                 binding.progressWrap.setVisibility(View.VISIBLE);                 binding.btnStart.setVisibility(View.GONE);//即将要请求网络,说明有人调用了播放了.这一般是耗时的,第一次播放一个数据源才回调             }             @Override             public void onVideoPausedMainThread() {                 binding.iv.setVisibility(View.VISIBLE);                 binding.progressWrap.setVisibility(View.GONE);                 binding.btnStart.setVisibility(View.VISIBLE);//即将要请求网络,说明有人调用了播放了.这一般是耗时的,第一次播放一个数据源才回调             }             @Override             public void onVideoStartedMainThread() {                 binding.btnStart.setVisibility(View.GONE);//即将要请求网络,说明有人调用了播放了.这一般是耗时的,第一次播放一个数据源才回调             }             @Override             public void onInfo(MediaPlayer mp, int what, int extra) {                 if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {//解决白屏问题                     binding.iv.setVisibility(View.INVISIBLE);                     binding.progressWrap.setVisibility(View.GONE);                 }             }         }); 
 
这里不会泄露,因为每次滑动到下一个视频,那么上一个视频的所有监听都会被移除、销毁。
ok列表播放的就到这里了,但是可能还会有一些体验需要优化,特别是处理继续播放的时候。 我这是高仿微视,他那个整个播放进度是在一个tab选项卡的上面,当缓冲的时候是进度从中间往两边散开,循环模式,所以播放进度这里不需要单独再写,而是在上面的管理器代码里面控制fragmet进度横条的显示,要知道整个进度特效如何实现的朋友可以看看我的github的allproject 目录导航
2018-4-30 17:41:34 其实这个项目还有很多不足,毕竟只是实现了列表播放,为了做优化,我的demo做了一个可显示进度显示时间,可暂停播放继续播放的 demo.可以去github下载看看。和大部分播放器一样,在界面销毁的时候调用销毁方法就可以解决泄露问题了