Exoplayer+Exomedia之玩转视频播放事件监听

2023-10-29

说明

  • 视频播放事件包括两个部分:1.播放器本身的事件(开始、暂停、结束播放等) 2.用户动作触发的事件(拖拽进度条、点击屏幕等)
  • 播放事件监听的途径主要是通过视频播放框架(或开发者自定义)的控制器来实现的。
  • 控制器是指操作播放器的组件(按钮、进度条等)的容器。
  • 事件的监听经常与视频当前时间配合使用。
  • 本文基于Exoplayer+Exomedia实现视频事件监听。

关键点

VideoView与视频时间、播放进度相关的主要方法。

  1. 获取视频当前时间
long getCurrentPosition()
  1. 获取视频总时长
long getDuration()
  1. 控制播放进度
void seekTo(long millis)

实现接口

包含VideoView的Activity请实现接口,全部接口及回调如下所示,实际使用中请挑选所需接口实现(若有遗漏请谅解).

public class XunshiVideoDemoActivity extends AppCompatActivity 
        implements 
        ExoPlayerListener,
        VideoControlsSeekListener,
        VideoControlsButtonListener,
        VideoControlsVisibilityListener,
        OnCompletionListener,
        OnPreparedListener,
        OnBufferUpdateListener {

    @Override
    public void onStateChanged(boolean playWhenReady, int playbackState) {
        
    }

    @Override
    public void onError(ExoMediaPlayer exoMediaPlayer, Exception e) {

    }

    @Override
    public void onVideoSizeChanged(int width, int height, int unAppliedRotationDegrees, float pixelWidthHeightRatio) {

    }

    @Override
    public void onBufferingUpdate(@IntRange(from = 0, to = 100) int percent) {

    }

    @Override
    public void onCompletion() {

    }

    @Override
    public void onPrepared() {

    }

    @Override
    public void onSeekComplete() {

    }

    @Override
    public boolean onPlayPauseClicked() {
        return false;
    }

    @Override
    public boolean onPreviousClicked() {
        return false;
    }

    @Override
    public boolean onNextClicked() {
        return false;
    }

    @Override
    public boolean onRewindClicked() {
        return false;
    }

    @Override
    public boolean onFastForwardClicked() {
        return false;
    }

    @Override
    public boolean onSeekStarted() {
        return false;
    }

    @Override
    public boolean onSeekEnded(long seekTime) {
        return false;
    }

    @Override
    public void onControlsShown() {

    }

    @Override
    public void onControlsHidden() {

    }
}

设置监听

//1.控制器的监听
mVideoView.getVideoControls().setVisibilityListener(this);
mVideoView.getVideoControls().setSeekListener(this);
mVideoView.getVideoControls().setButtonListener(this);

//2.播放器的监听
mVideoView.setOnCompletionListener(this);
mVideoView.setOnSeekCompletionListener(this);
mVideoView.setOnPreparedListener(this);
mVideoView.setOnBufferUpdateListener(this);

这里的参数this是因为Activity实现了接口,也可以直接传匿名函数如下:

mVideoView.setOnBufferUpdateListener(new OnBufferUpdateListener() {
            @Override
            public void onBufferingUpdate(@IntRange(from = 0, to = 100) int percent) {
                //do something
            }
        });

详细说明

播放器监听类

  1. ExoPlayerListener
    与Exoplayer的addListener回调类似,监听了视频播放状态变化、报错、尺寸变化、进度条拖拽结束。
mVideoView.setOnSeekCompletionListener(this);
@Override
    public void onStateChanged(boolean playWhenReady, int playbackState) {
        //视频播放状态
    }

    @Override
    public void onError(ExoMediaPlayer exoMediaPlayer, Exception e) {
        //报错
    }

    @Override
    public void onVideoSizeChanged(int width, int height, int unAppliedRotationDegrees, float pixelWidthHeightRatio) {
        //尺寸
    }

    @Override
    public void onSeekComplete() {
        //拖拽进度条结束
    }
  1. OnCompletionListener
    视频加载并且播放完毕时回调.
mVideoView.setOnCompletionListener(this);
@Override
    public void onCompletion() {
      
    }
  1. OnPreparedListener
    视频准备完毕可以播放时回调.经常在这里获取视频播放长度.
mVideoView.setOnPreparedListener(this);
@Override
    public void onPrepared() {
        Log.d(TAG, "视频时长=" +  mVideoView.getDuration());
    }
  1. OnBufferUpdateListener
    视频缓冲时回调/视频播放中不断的回调,非常适合监听播放当前时刻--->getCurrentPosition()
mVideoView.setOnBufferUpdateListener(this);
@Override
    public void onBufferingUpdate(@IntRange(from = 0L, to = 100L) int percent) {
        Log.d(TAG, "当前播放时刻=" + mVideoView.getCurrentPosition());
    }
  • OnBufferUpdateListener监听Log示例:
    06-30 16:46:44.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():478
    06-30 16:46:45.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():1479
    06-30 16:46:46.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():2474
    06-30 16:46:47.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():3477
    06-30 16:46:48.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():4484
    06-30 16:46:49.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():5469
    06-30 16:46:50.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():6492
    06-30 16:46:51.570 15602-15602/com.xunshi.videodemo D/VideoActivity: onBufferingUpdate.getCurrentPosition():7492
    可以看出此getCurrentPosition()的值随播放时刻变化而变化,说明此回调是在持续进行监听的.

注意!

此方法在视频播放完毕后即停止监听,restart()视频也不会再次监听!如果想重新监听有两种方法:

  1. 释放视频资源,重新加载;
  2. 利用OnBufferUpdateListener持续监听的特性,在视频播放完毕前暂停,此时restart()视频即可再次监听了!总时间减去当前时间:getDuration() - getCurrentPosition()  >= 1000毫秒时说明视频没有播放完毕。
@Override
    public void onBufferingUpdate(@IntRange(from = 0L, to = 100L) int percent) {
        Log.d(TAG, "onBufferingUpdate.getCurrentPosition():" + mVideoView.getCurrentPosition());

        if (mVideoView.getDuration() - mVideoView.getCurrentPosition() < 1000) {
            //计算时长小于1000毫秒
            //视同视频播放完毕
            return;
        }
    }

控制器监听类

  1. VideoControlsSeekListener
    监听进度条拖拽的开始与结束.
mVideoView.getVideoControls().setSeekListener(this);
@Override
    public boolean onSeekStarted() {
        //开始拖拽时刻
        Log.d(TAG, "开始拖拽时刻=" + mVideoView.getCurrentPosition());
        return false;
    }

    @Override
    public boolean onSeekEnded(long seekTime) {
        //结束拖拽时刻
        Log.d(TAG, "结束拖拽时刻=" + mVideoView.getCurrentPosition());
        return false;
    }
  1. VideoControlsButtonListener
    控制器按钮点击事件监听.
mVideoView.getVideoControls().setButtonListener(this);
@Override
    public boolean onPlayPauseClicked() {
        //开始/暂停
        return false;
    }
    
    @Override
    public boolean onPreviousClicked() {
        //回退
        return false;
    }

    @Override
    public boolean onNextClicked() {
        return false;
    }

    @Override
    public boolean onRewindClicked() {
        //前进
        return false;
    }

    @Override
    public boolean onFastForwardClicked() {
        //快进
        return false;
    }

3.VideoControlsVisibilityListener
控制器可见性监听.

mVideoView.getVideoControls().setVisibilityListener(this);
@Override
    public void onControlsShown() {

    }

    @Override
    public void onControlsHidden() {

    }

其他

相关文章请点击下面链接:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Exoplayer+Exomedia之玩转视频播放事件监听 的相关文章

  • 20181220_eglSwapBuffers详解

    eglSwapBuffers详解 问题来自eglSwapBuffers是否有等待 如果调用eglSwapBuffers的话 是不是会导致帧率下降 2 7 1 BootAnimation中的调用 之所以需要了解这个api的具体实现 因为我们需
  • 史上最全的2023年最新版Android面试题集锦(含答案解析)

    前言 又到了一年的金三银四黄金求职季 虽说今年以来 经济回暖 但行业岗位缺口紧缩的趋势恢复还需一段时间 尤其对于Android开发而言 想要跳槽到一个高薪岗位更是难上加难 因此 想要杀出重围 必然要有万全的准备 除了一份美观的简历 还必须刷
  • ListView具有多种item布局——实现微信对话列 .

    这篇文章的效果也是大家常见的 各种通讯应用的对话列表都是这种方式 像微信 whatsapp 易信 米聊等 我们这篇文章也权当为回忆 形成简单的笔记 这篇文章参考了2009年Google IO中的 TurboChargeYourUI How
  • 当面试官说 “你还有什么问题想问的” ,你该如何回答?

    程序员面试时经常会听到面试官说一些套话 比如 今天的面试就到这里了 回去等通知吧 你还有什么问题想问我的吗 如果这道题不会做 那么我们也可以换一道 今天我们要说的是大多数面试官都会说的一句话 你还有什么问题想问的 这是一个老生常谈的问题 之
  • Each module has to have a unique path

    在android工作中从仓库中down下来的时候 首次运行出现 Each module has to have a unique path 使用android studio开发工具 因为同事一起把 iml文件给上传上去了 每次builde都
  • android使用隐藏api的方法(使用被@hide的api)

    前言 一开始需要说明的是 Google之所以要将一些API隐藏 指加上 hide标记的public类 方法或常量 是有原因的 其中很大的原因就是Android系统本身还在不断的进化发展中 从1 0 1 1到现在即将问世的Android 2
  • 史上最全Android渲染机制讲解(长文源码深度剖析)

    前言 渲染机制是Android操作系统很重要的一环 本系列通过介绍应用从启动到渲染的流程 揭秘Android渲染原理 问题 1 vsync如何协调应用和SurfaceFlinger配合来完成UI渲染 显示 App接收vsync后要做哪些工作
  • 【Android开发】toast提示

    什么是Toast 在屏幕下方浮现出一个窗口 显示一段时间后又消失 这个可视化组件叫做 Toast 它主要用于提示用户某种事件发生了 如何在添加Toast 最关键的是在事件处理逻辑中加两条语句 定义一个Toast 用makeText 设置要浮
  • Android快速开发框架-ZBLibrary 源码分享

    坐标标准库ZBLibrary 是一个MVP架构的Android快速开发框架 提供一套开发标准 UI Data Listener 以及模板和工具类并规范代码 封装层级少 简单高效兼容性好 一句代码就可实现全局滑动返回 可重写 集成方便快捷的照
  • Android中音频元数据的采集,及RTMP推流

    在用手机做直播推流时 不管是录屏直播 还是摄像头直播 都要用到音频的元数据 在Android中 可以借助AudioRecord来采集音频数据 然后通过faac编码库 加入用的音频编码器是faac 将编码后的数据交给RTMP去封包后发送给服务
  • 26.kotlin的get和set方法

    1 kotlin类中的get和set方法 fun main args Array
  • Android 避免耗时操作及解决办法

    Android耗时操作 我们可以通过几种方式实现 IntentService IntentService 与Service的不同之处在于IntentService是可以执行耗时任务的 而Service不能够执行耗时任务 否则会出现ANR异常
  • Flutter 完整示例

    经过这一段对 Flutter 的了解和接触 掌握如何完整使用 Flutter 开发一个项目 实际上 在 Flutter 中 一切皆 widget 我们的界面都是由各种 widget 堆叠出来的 一个 Flutter 工程涉及以下几个要点 工
  • java倒叙遍历list

    for int i list size 1 i gt 0 i System out println list get i
  • APP启动页隐私弹窗实现说明

    最近审核严禁 腾讯应用市场要求APP在启动页增加隐私政策和用户协议 用户从腾讯应用市场上下载APP 第一加载的时候弹窗 不然审核就不给过 样式大概如下 用户若点击不同意的时候 无法进入APP内部 下面把实现的代码贴上来 1 加个判断 其他应
  • Android中的Drawable资源—— InsetDrawable

    InsetDrawable 表示一个drawable嵌入到另外一个drawable内部 并且在内部留一些间距 存放位置 res drawable 使用方式 在Java文件中 R drawable filename 在xml布局文件中 pac
  • 【Android开发】一文全面解析Framework层

    前言 上一篇文章从Native角度讲解了Android进程管理的相关概念 本文将继续从上层的Framework中的进程启动 销毁场景和优先级处理 以及它们与四大组件的种种关联 来逐步解析Android进程管理的其他关键要素 进程的启动 An
  • 【Android11系统开发】上层app通过AIDL监听framework数据

    一 适用场景 在Android系统开发中 需要监听按键 触摸 或者可见窗口大小变化等需求时 你会考虑什么方法来实现呢 通过广播的方式可以实现 但是效果可能并不好 AIDL可以实现跨进程通讯 可以解决以上需求 下面重点分析下如何具体实现 以实
  • Android的组件、布局学习

    介绍 公司组织架构调整 项目组需要承接其他项目组的android项目 负责维护和开发新需求 故学习下基础语法和项目开发 组件学习 Toolbar header布局部分 就是app最顶部的部分 他的显示与否 是与F androidProjec
  • Android的基础开发

    基础开发 listView ListView就是列表条目 可以向下滚动 也可以点击 首先设置两个视图布局 activity main2 xml 充当容器 ListView

随机推荐

  • ASP.NET页面之间传递值的几种方式

    页面传值是学习asp net初期都会面临的一个问题 总的来说有页面传值 存储对象传值 ajax 类 model 表单等 但是一般来说 常用的较简单有QueryString Session Cookies Application Server
  • sony闪存卡/内存卡格式化修复工具

    索尼的USM formatterP工具用于格式化PhISOn主控的SONY闪存卡 修复内存卡无法格式化 使用时需要先备份所选分区上的所有数据 在格式化完成后数据将全部丢失 先选择要格式化的分区 再选择格式化的文件类型 sony闪存卡 内存卡
  • java 将天数转成月_java获取当月天数,指定年月的天数,指定日期获取对应星期(转)...

    分类 Java2012 12 25 23 52 3201人阅读 package com import java text SimpleDateFormat import java util Calendar import java util
  • 线程、多线程学习总结

    线程 多线程 1 基本概念 程序 线程 进程 1 1 程序 线程 进程 程序 一段静态代码 静态对象 进程 正在运行中的一个程序 线程 进程细化分为线程 作为调度和执行的单位 每个线程拥有独立的运行栈和程序计数器 并行 多个CPU同时执行多
  • SpringBoot从入门到精通---基础篇

    SpringBoot 一 基础篇 1 1 入手项目 注意 如果这里SpringBoot1Application 启动程序 是灰色的 你右键点击pom xml把它作为Maven项目就可以启动 BookController类中的代码 启动后访问
  • springboot @Autowired 注入为null 的原因与解决方式

    有时候我们在某个类用 Autowired 进行注入时 会发现注入参数为null 这时候会有疑惑 可能存在的原因 1 该类没有托管给spring 管理 一般在类的上面添加 Component 就可以了 2 你的这个类有被new出来的实例的 n
  • Java之BigInteger的用法

    目录 Java之BigInteger用法 一 常用方法 二 进制转换 Java之BigInteger用法 BigInteger在Java中用于操作大整数 当一个数超过了Long表示的最大范围时就可以考虑使用BigInteger来操作 Big
  • unity 设置一键重启

    以前的游戏里用过 后来查reference怎么也找不到当时用的代码了 重新看了一下工程发现是用playmaker实现的
  • [288]关于MySQL的1064错误

    MySQL的1064错误是SQL语句写的有问题时出现的 即SQL的语法错误 笔者常常使用MySQL python这个库来对MySQL进行操作 代码中报这个错误的一般是cursor execute sql param 这一行 这种参数式执行S
  • Vue的Ui框架之Mint-UI的使用方法

    基于Vue的Ui框架 饿了么公司基于vue开发的vue的Ui组件库 Element Ui 基于vue pc端的UI框架 MintUi 基于vue 移动端的ui框架 mintUI的使用 1 找官网 2 安装 npm install mint
  • stm32 freeRTOS lwip TCP快速发送,内存泄露问题

    现象1 发送缓慢 tcp write之后要等200多ms才能过发送出去 而且粘包严重 解决办法 tcp write之后 立马调用tcp output tcp就会立马发送 tcp write tcp output 现象2 持续快速发送和接受T
  • linux top VIRT RES SHR SWAP DATA内存参数详解

    总结 VIRT 虚拟内存中含有共享库 共享内存 栈 堆 所有已申请的总内存空间 RES 是进程正在使用的内存空间 栈 堆 申请内存后该内存段已被重新赋值 SHR 是共享内存正在使用的空间 SWAP 交换的是已经申请 但没有使用的空间 包括
  • cookie的读写设计和浏览器控制台Application设计不一致?

    问题描述 在做需求联调的时候发现 用https的链接登录状态验证正常 但是在http协议下 会出现set cookie失败的情况 导致登录状态验证失败 查看控制台 报错如下 提示 会覆盖具有 Secure 属性的cookie 于是在控制台下
  • C语言:以分号结尾的诗

    目录 前言 1 从Hello world开始 2 数据的类型与运算 2 1 整形在内存中的存储 2 1 1 从二进制说起 2 1 2 数据类型 2 1 2 1 数据类型家族 2 1 2 2 比特 字节 2 1 3 原码 反码 补码 2 1
  • cookie保存,json、字符串相互转换

    cookie读写操作 addcookie函数中 对text进行了eacape编码 方便在各种浏览器 下都可以读取 所以取值的时候需要unescape 解码 function getCookie name var strCookie docu
  • Windows下性能最好的I/O模型——完成端口

    Windows下性能最好的I O模型 完成端口 I O模型 完成端口 设计目的 常见的网络通信分为两种 同步和异步 在同步通信中 每一次接受数据都会导致主线程的挂起 从而阻塞住了其他操作 为了解决这一问题 我们通常会采取同步通信 多线程的策
  • 一个关于Python字符串格式化输出的练习

    请实现一个程序 实现如下需求点 1 程序开始的时候提示用户输入学生年龄信息 格式如下 Jack Green 21 Mike Mos 9 我们假设 用户输入 上面的信息 必定会遵守下面的规则 学生信息之间用分号隔开 分号前后可能有不定数量的空
  • 延时函数中用全局变量还是用局部变量

    从不上系统角度 如果中断函数中没有调用延时函数 就都可以 但是如果中断函数中有用到延时函数 就用 局部变量 因此 全部使用局部变量最好
  • 一次磁盘占用率 100% 的排查记录

    一 排查磁盘占用率100 1 1 查看磁盘使用的大致情况 第一个命令就是 df h 来查看磁盘的占用情况 df 是 disk free 的缩写 用于显示目前在 Linux 系统上的文件系统磁盘的使用情况统计 如下图所示 可以看到磁盘占用率
  • Exoplayer+Exomedia之玩转视频播放事件监听

    说明 视频播放事件包括两个部分 1 播放器本身的事件 开始 暂停 结束播放等 2 用户动作触发的事件 拖拽进度条 点击屏幕等 播放事件监听的途径主要是通过视频播放框架 或开发者自定义 的控制器来实现的 控制器是指操作播放器的组件 按钮 进度