我这文章暂时是打广告的,要使用列表播放的朋友
http://github.com/qssq/videoplayer
视频效果http://www.iqiyi.com/w_19rxx2xtg5.html
要做2件事情,第一 要监听recyclerview的滚动状态变为空闲的时候寻找videoview 进行播放
第二 ,要再recyclerview的布局改变的时候也寻找videoview进行播放
第三 让视频无缝无白屏闪屏播放
所以我就不用国内的这些第三方了,感觉摸不着头脑,y因为搞不到为何findview之后调用播放按钮竟然毛线反应没有,
于是找到了一个国外的,但是有很多坑 我修改了好几天,解决了白闪问题,增加了缓冲的显示,增加了点击播放暂停的控制
使用方法
compile 'cn.qssq666:video-player-manager:0.5'
如果多个界面都有列表视频播放 mVideoPlayerManager那么在界面不可见的时候各位要进行暂停或者销毁
创建单例管理器
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的滚动
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); } });自动播放的具体逻辑
private void autoPlayVideo(RecyclerView view) { RecyclerView.LayoutManager layoutManager = view.getLayoutManager(); int actualCurrentPosition = binding.viewpager.getCurrentPosition(); metaData metaData = new metaData() { }; GenericDataBindViewHolder页面声明周期控制holder = (GenericDataBindViewHolder ) 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()); }
@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布局
监听视频透明封面的点击
请注意,这里播放视频是用管理器去 *** 作播放,而不是通过布局的videoPlayer2
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);添加监听
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下载看看。和大部分播放器一样,在界面销毁的时候调用销毁方法就可以解决泄露问题了
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)