开源播放器GSYVideoPlayer + ViewPager2 源码解析
开源播放器GSYVideoPlayer + ViewPager2 源码解析
- 前言
- 一、GSYVideoPlayer🔥🔥🔥是什么?
- 二、源码解析
- 1.ViewPager2Activity
- 总结
前言
本文介绍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中,我们可以看到相关代码。
代码如下(示例):
viewPagerAdapter = new ViewPagerAdapter(this, dataList);binding.viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);binding.viewPager2.setAdapter(viewPagerAdapter);binding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Overridepublic void onPageSelected(int position) {super.onPageSelected(position);//大于0说明有播放int playPosition = GSYVideoManager.instance().getPlayPosition();if (playPosition >= 0) {//对应的播放列表TAGif (GSYVideoManager.instance().getPlayTag().equals(RecyclerItemNormalHolder.TAG)&& (position != playPosition)) {GSYVideoManager.releaseAllVideos();playPosition(position);}}}});binding.viewPager2.post(new Runnable() {@Overridepublic 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这个方法出现了两次,并且从名字中可以看出是播放的方法,我们接下来看看这个方法干了些什么。
private void playPosition(int position) {binding.viewPager2.postDelayed(new Runnable() {@Overridepublic 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类。
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() {@Overridepublic void onPrepared(String url, Object... objects) {super.onPrepared(url, objects);if (!gsyVideoPlayer.isIfCurrentIsFullscreen()) {//静音GSYVideoManager.instance().setNeedMute(true);}}@Overridepublic void onQuitFullscreen(String url, Object... objects) {super.onQuitFullscreen(url, objects);//全屏不静音GSYVideoManager.instance().setNeedMute(true);}@Overridepublic void onEnterFullscreen(String url, Object... objects) {super.onEnterFullscreen(url, objects);GSYVideoManager.instance().setNeedMute(false);gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]);}}).build(gsyVideoPlayer);//增加titlegsyVideoPlayer.getTitleTextView().setVisibility(View.GONE);//设置返回键gsyVideoPlayer.getBackButton().setVisibility(View.GONE);//设置全屏按键功能gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {@Overridepublic 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
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支持多种开源播放器,具有较好的维护和文档,但使用时需注意不同版本对应问题。
相关文章:

开源播放器GSYVideoPlayer + ViewPager2 源码解析
开源播放器GSYVideoPlayer ViewPager2 源码解析 前言一、GSYVideoPlayer🔥🔥🔥是什么?二、源码解析1.ViewPager2Activity 总结 前言 本文介绍GSYVideoPlayer源码中关于ViewPager2 GSYVideoPlayer 实现的滑动播放列表的实现原理。…...

重启路由器可以解决N多问题?
为什么重启始终是路由器问题的首要解决方案? 在日常的工作学习工作中,不起眼的路由器是一种相对简单的设备,但这仍然是我们谈论的计算机。 这种廉价的塑料外壳装有 CPU、随机存取存储器 (RAM)、只读存储器 (ROM) 和许多其他组件。 该硬件运行预装的软件(或固件)来管理连接…...
Python WebSocket 客户端教程
WebSocket 是一种在客户端和服务器之间实现双向通信的协议,常用于实时聊天、实时数据更新等场景。Python 提供了许多库来实现 WebSocket 客户端,本教程将介绍如何使用 Python 构建 WebSocket 客户端。 什么是 WebSocket WebSocket 是一种基于 TCP 协议…...
洛谷 P2984 [USACO10FEB] Chocolate Giving S
文章目录 [USACO10FEB] Chocolate Giving S题面翻译题目描述输入格式输出格式 题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 题意解析CODE给点思考 [USACO10FEB] Chocolate Giving S 题面翻译 题目链接:https://www.luogu.com.cn/problem/P2984 题目描…...

【专题】【数列极限】
【整体思路】 【常用不等式】...
oracle基础系统学习文章目录
oracle基础系统学习——点击标题可跳转对应文章 01.CentOS7静默安装oracle11g 02.Oracle的启动过程 03.从简单的sql开始 04.Oracle的体系架构 05.Oracle数据库对象 06.Oracle数据备份与恢复 07.用户和权限管理 08.Oracle的表 09.Oracle表的分区 10.Oracle的同义词与序列 11.Or…...

长度最小的子数组(Java详解)
目录 题目描述 题解 思路分析 暴力枚举代码 滑动窗口代码 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条…...

计算机组成学习-数据的表示和运算总结
复习本章时,思考以下问题: 1)在计算机中,为什么要采用二进制来表示数据?2)计算机在字长足够的情况下能够精确地表示每个数吗?若不能,请举例说明。3)字长相同的情况下,浮点数和定点数的表示范围…...
目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】机器视觉(基础篇)(八)
目录 前言 知识储备 机器视觉学习路线 视觉算法流程...
【4】基于多设计模式下的同步异步日志系统-框架设计
7. 日志系统框架设计 本项⽬实现的是⼀个多日志器日志系统,主要实现的功能是让程序员能够轻松的将程序运行日志信息落地到指定的位置,且⽀持同步与异步两种方式的日志落地方式。 项目的框架设计将项目分为以下几个模块来实现。 日志等级模块 日志等级模…...

Jupyter Markdown 插入图片
首先截图 注意 这一步是关键的!! 它需要使用电脑自带的截图,用qq啊vx啊美图秀秀那些都不行哦。 截图之后复制: 然后快捷键粘贴到jupyter里面,它会生成一段代码(没有代码就是说截图形式不对)&a…...

web自动化 -- pyppeteer
由于Selenium流行已久,现在稍微有点反爬的网站都会对selenium和webdriver进行识别,网站只需要在前端js添加一下判断脚本,很容易就可以判断出是真人访问还是webdriver。虽然也可以通过中间代理的方式进行js注入屏蔽webdriver检测,但…...

Java 数组另类用法(字符来当数组下标使用)
一、原因 看力扣的时候发现有位大佬使用字符来当数组下标使用。 class Solution {public int lengthOfLongestSubstring(String s) {int result 0;int[] hash new int[130];int i 0;for(int j 0; j < s.length(); j) {while(hash[s.charAt(j)] > 0) {hash[s.charAt…...
error转string
1 概述 在golang中,error类型是非常常见的一种数据类型。在开发过程中,经常会遇到需要将error类型转换成string类型的情况。本文主要介绍几种常见的golang error转string的方法。 2 使用Error()函数 在golang中,Error()函数是error类型的一…...
Android监听用户的截屏、投屏、录屏行为
Android监听用户的截屏、投屏、录屏行为 一.截屏 方案一:使用系统广播监听截屏操作 从Android Q(10.0)开始,Intent.ACTION_SCREEN_CAPTURED_CHANGED字段不再被支持。这是因为Google在安卓10 中引入了一个新的隐私限制&#…...
MATLAB算法实战应用案例精讲-【路径规划】 图搜索算法
目录 前言 几个高频面试题目 运动规划、路径规划、轨迹规划对比 1. 运动规划 2. 路径规划VS轨迹规划...
Elasticsearch-Kibana使用教程
1.索引操作 1.1创建索引 PUT /employee {"settings": {"index": {"refresh_interval": "1s","number_of_shards": 1,"max_result_window": "10000","number_of_replicas": 0}},"mappi…...

mysql(八)docker版Mysql8.x设置大小写忽略
Mysql 5.7设置大小写忽略可以登录到Docker内部,修改/etc/my.cnf添加lower_case_table_names1,并重启docker使之忽略大小写。但MySQL8.0后不允许这样,官方文档记录: lower_case_table_names can only be configured when initializ…...
KALI LINUX攻击与渗透测试
预计更新 第一章 入门 1.1 什么是Kali Linux? 1.2 安装Kali Linux 1.3 Kali Linux桌面环境介绍 1.4 基本命令和工具 第二章 信息收集 1.1 网络扫描 1.2 端口扫描 1.3 漏洞扫描 1.4 社交工程学 第三章 攻击和渗透测试 1.1 密码破解 1.2 暴力破解 1.3 漏洞利用 1.4 …...

vue之mixin混入
vue之mixin混入 mixin是什么? 官方的解释: 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...