开源播放器GSYVideoPlayer + ViewPager2 源码解析
前言
本文介绍GSYVideoPlayer源码中关于ViewPager2 +GSYVideoPlayer 实现的滑动播放列表的实现原理。
本文使用的版本为gsyVideoPlayerVersion = "7.1.4"
一、GSYVideoPlayer🔥🔥🔥是什么?
github地址: https://github.com/CarGuo/GSYVideoPlayer
让我们看看介绍:
视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS支持,支持弹幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频本身自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持,支持列表播放 ,直接添加控件为封面,列表全屏动画,视频加载速度,列表小窗口支持拖动,动画效果,调整比例,多分辨率切换,支持切换播放器,进度条小窗口预览,其他一些小动画效果,rtsp、concat、mpeg。(总结,高端大气上档次)
让我们看看作者:
让我们看看文档:
优点
- 支持好几种开源播放器,集大成者
- 可以按需引用所需要的依赖,这样一来包体积不会太大
- 作者维护很勤快,有什么问题issues,作者也会帮忙看看
- 文档写的很清楚不需要额外查资料,实在不懂代码拉下来一跑,对照着代码基本上就能理解了
缺点:
-有一些版本对应会有不同的问题,比如我使用的时候用了最新的依赖,按照文档不能播放rtsp流,降低了依赖过后就可以播放了。
如果想使用其他播放器的可以看看我的这篇文章
安卓的播放器对比与选型(vlc,EXOplayer,Ijkplayer,GSYVideoPlayer)详细过程
二、源码解析
1.ViewPager2Activity
在ViewPager2Activity中,我们可以看到相关代码。
代码如下(示例):
kotlin
viewPagerAdapter = new ViewPagerAdapter(this, dataList);
binding.viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
binding.viewPager2.setAdapter(viewPagerAdapter);
binding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
//大于0说明有播放
int playPosition = GSYVideoManager.instance().getPlayPosition();
if (playPosition >= 0) {
//对应的播放列表TAG
if (GSYVideoManager.instance().getPlayTag().equals(RecyclerItemNormalHolder.TAG)
&& (position != playPosition)) {
GSYVideoManager.releaseAllVideos();
playPosition(position);
}
}
}
});
binding.viewPager2.post(new Runnable() {
@Override
public void run() {
playPosition(0);
}
});
}
这段代码是在使用Android中的ViewPager2来创建一个滑动页面效果。ViewPager2是Android提供的一个用于实现滑动页面效果的组件。下面是对这段代码的逐行解释:
viewPagerAdapter = new ViewPagerAdapter(this, dataList);
这一行是创建一个ViewPager的适配器,其中this
是指当前的Activity,dataList
是用来提供数据给ViewPager的列表。binding.viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
这一行是设置ViewPager的滑动方向为垂直滑动。binding.viewPager2.setAdapter(viewPagerAdapter);
这一行是将刚刚创建的ViewPager适配器设置到ViewPager上。binding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {...});
这一行是注册一个页面改变的回调。当ViewPager的页面发生改变时,会回调这个接口的实现。- 在回调的实现中,
int playPosition = GSYVideoManager.instance().getPlayPosition();
获取当前播放的位置。 if (playPosition >= 0) {...}
这个判断是为了确认当前有视频播放状态是正常的。- 在这个if语句中,首先判断当前正在播放的视频的Tag是否等于RecyclerItemNormalHolder的Tag,如果不是,那么就释放所有的视频并跳转到当前的位置。这个逻辑是为了处理当页面发生改变时,如果当前播放的视频不在这个页面上,就停止播放并跳转到当前页面的视频。
binding.viewPager2.post(new Runnable() {...});
这一行代码在ViewPager的Looper中执行一个Runnable,这个Runnable会在ViewPager的UI线程中运行。- 在Runnable的实现中,调用
playPosition(0);
方法,是为了在页面加载完成后自动播放位于第一个位置的视频。
在上面的代码中,我们可以看到playPosition这个方法出现了两次,并且从名字中可以看出是播放的方法,我们接下来看看这个方法干了些什么。
kotlin
private void playPosition(int position) {
binding.viewPager2.postDelayed(new Runnable() {
@Override
public void run() {
RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.
viewPager2.getChildAt(0)).findViewHolderForAdapterPosition(position);
if (viewHolder != null) {
RecyclerItemNormalHolder recyclerItemNormalHolder = (RecyclerItemNormalHolder) viewHolder;
recyclerItemNormalHolder.getPlayer().startPlayLogic();
}
}
}, 50);
}
可以看到playPosition通过findViewHolderForAdapterPosition方法找到了当前viewPager2对应的viewHolder,通过viewHolder的getPlayer()方法获取到了播放器,并开始了播放,我们再去看看RecyclerItemNormalHolder类。
kotlin
package com.example.gsyvideoplayer.holder;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.example.gsyvideoplayer.R;
import com.example.gsyvideoplayer.databinding.ActivityDetailExoSubtitlePlayerBinding;
import com.example.gsyvideoplayer.model.VideoModel;
import com.example.gsyvideoplayer.video.SampleCoverVideo;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack;
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
import java.util.HashMap;
import java.util.Map;
/**
* Created by guoshuyu on 2017/1/9.
*/
public class RecyclerItemNormalHolder extends RecyclerItemBaseHolder {
public final static String TAG = "RecyclerView2List";
protected Context context;
SampleCoverVideo gsyVideoPlayer;
ImageView imageView;
GSYVideoOptionBuilder gsyVideoOptionBuilder;
public RecyclerItemNormalHolder(Context context, View v) {
super(v);
this.context = context;
gsyVideoPlayer = v.findViewById(R.id.video_item_player);
imageView = new ImageView(context);
gsyVideoOptionBuilder = new GSYVideoOptionBuilder();
}
public void onBind(final int position, VideoModel videoModel) {
String url;
String title;
if (position % 2 == 0) {
url = "https://pointshow.oss-cn-hangzhou.aliyuncs.com/McTk51586843620689.mp4";
title = "这是title";
} else {
url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
title = "哦?Title?";
}
Map<String, String> header = new HashMap<>();
header.put("ee", "33");
//防止错位,离开释放
//gsyVideoPlayer.initUIState();
gsyVideoOptionBuilder
.setIsTouchWiget(false)
//.setThumbImageView(imageView)
.setUrl(url)
.setVideoTitle(title)
.setCacheWithPlay(false)
.setRotateViewAuto(true)
.setLockLand(true)
.setPlayTag(TAG)
.setMapHeadData(header)
.setShowFullAnimation(true)
.setNeedLockFull(true)
.setPlayPosition(position)
.setVideoAllCallBack(new GSYSampleCallBack() {
@Override
public void onPrepared(String url, Object... objects) {
super.onPrepared(url, objects);
if (!gsyVideoPlayer.isIfCurrentIsFullscreen()) {
//静音
GSYVideoManager.instance().setNeedMute(true);
}
}
@Override
public void onQuitFullscreen(String url, Object... objects) {
super.onQuitFullscreen(url, objects);
//全屏不静音
GSYVideoManager.instance().setNeedMute(true);
}
@Override
public void onEnterFullscreen(String url, Object... objects) {
super.onEnterFullscreen(url, objects);
GSYVideoManager.instance().setNeedMute(false);
gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]);
}
}).build(gsyVideoPlayer);
//增加title
gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE);
//设置返回键
gsyVideoPlayer.getBackButton().setVisibility(View.GONE);
//设置全屏按键功能
gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
resolveFullBtn(gsyVideoPlayer);
}
});
gsyVideoPlayer.loadCoverImageBy(R.mipmap.xxx2, R.mipmap.xxx2);
}
/**
* 全屏幕按键处理
*/
private void resolveFullBtn(final StandardGSYVideoPlayer standardGSYVideoPlayer) {
standardGSYVideoPlayer.startWindowFullscreen(context, true, true);
}
public SampleCoverVideo getPlayer() {
return gsyVideoPlayer;
}
}
为了让读者看的更清晰,我提了整个类,可以看到,在自身初始化时就对gsyVideoPlayer进行了初始化,并且在数据绑定的onBind方法中为了防止错位,专门设置了gsyVideoOptionBuilder,而getPlayer方法只是把gsyVideoPlayer返回。所以,实现列表播放的关键代码其实就是gsyVideoOptionBuilder
kotlin
gsyVideoOptionBuilder
.setIsTouchWiget(false)
//.setThumbImageView(imageView)
.setUrl(url)
.setVideoTitle(title)
.setCacheWithPlay(false)
.setRotateViewAuto(true)
.setLockLand(true)
.setPlayTag(TAG)
.setMapHeadData(header)
.setShowFullAnimation(true)
.setNeedLockFull(true)
.setPlayPosition(position)
总结
本文主要介绍了开源播放器GSYVideoPlayer和ViewPager2的结合使用,实现滑动播放列表的原理。通过对ViewPager2Activity、RecyclerItemNormalHolder等类中的代码解析,了解了如何在ViewPager2中播放视频,关键代码为gsyVideoOptionBuilder。GSYVideoPlayer支持多种开源播放器,具有较好的维护和文档,但使用时需注意不同版本对应问题。