Android 13 - Media框架(2)- Demo App与MediaPlayer Api了解

2023-11-02

尝试用MediaPlayer写了一个播放demo,实现了网络流和本地流的播放。由于本人对app开发一窍不通,所以demo中很多内容是边查资料边写的,写的也比较杂乱,能够帮助理解api就行。这一节主要会记录demo开发中学到的内容,以及了解MediaPlayer Api。

1、demo效果

由于Android Studio的虚拟设备只支持API 30,所以demo的编写是基于Android R的,但是后续看的代码还是会基于Android T,这部分应该差的不是很多。

demo代码还没有完善(已发现问题还没处理),目前实现的效果如下,包含有以下几个内容:

  • 网络视频以及本地视频播放
  • 本地视频的seek,播放时间更新
  • 播放过程中窗口最大化
    请添加图片描述

代码可在github下载:MediaPlayerDemo-github
有积分的小伙伴也可在CSDN下载:MediaPlayerDemo-CSDN


2、demo实现过程中学到的相关内容

2.1、layout

  • FrameLayout 中的控件默认位置都是在左上角,可以通过 layout_marginLeft/Right/Bottom/Top 来控制空间边缘的距离;
  • layout_gravity 用于控制组件在当前容器中的位置,可以设置top|right|bottom|left
  • LinearLayout 可以将组件水平或垂直摆放,用layout_weight可以动态调整组件的大小,这时候layout_width需要设置为0;
  • 同一个layout中后面的组件会覆盖前面的组件;
  • dp 转 px 的方法如下:
    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

2.2、Manifest

如果需要访问内部存储,需要添加以下权限:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

同时application中还要添加:

android:requestLegacyExternalStorage="true"

打开app后需要给app赋予权限,否则仍不能访问存储。

访问Internet需要赋予如下权限:

<uses-permission android:name="android.permission.INTERNET" />

有了如上设定播放网络流仍会失败,还需在application添加:

android:usesCleartextTraffic="true"

播放页面横屏不能结束当前activity的生命周期,需要在activity中添加如下配置:

android:configChanges="orientation|screenSize"

android app默认的主题颜色是紫色,并且会有标题栏,我们可以修改 application 中的 theme主题,主题设置在themes.xml中。

2.3、Activity

这里要了解的是与Activity相关的方法,例如 onCreate、onStart、onPause、onResume、onDestory等,这些方法可以在Activity的基类AppCompatActivity中查找到,注意Override这些方法时需要调用它们的 super 方法。

启动MainActivity时,执行顺序如下:

2023-08-12 22:52:20.240 1790-1790/com.example.mediademo D/Demo_MainActivity: onCreate
2023-08-12 22:52:20.323 1790-1790/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:52:20.324 1790-1790/com.example.mediademo D/Demo_MainActivity: onResume

启动VideoActivity时,执行顺序如下:

2023-08-12 22:59:32.992 1928-1928/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:59:33.539 1928-1928/com.example.mediademo D/Demo_MainActivity: onStop

回到之前MainActivity时:

2023-08-12 22:59:41.757 1928-1928/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:59:41.758 1928-1928/com.example.mediademo D/Demo_MainActivity: onResume

退出app时(按返回键或者退出后台),会多执行一个 onDestroy 销毁资源:

2023-08-12 23:06:09.275 2334-2334/com.example.mediademo D/Demo_MainActivity: dispatchKeyEvent, keycode = 4
2023-08-12 23:06:09.275 2334-2334/com.example.mediademo D/Demo_MainActivity: keyCode = 4
2023-08-12 23:06:09.383 2334-2334/com.example.mediademo D/Demo_MainActivity: dispatchKeyEvent, keycode = 4
2023-08-12 23:06:09.394 2334-2334/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 23:06:09.940 2334-2334/com.example.mediademo D/Demo_MainActivity: onStop
2023-08-12 23:06:09.941 2334-2334/com.example.mediademo D/Demo_MainActivity: onDestroy

2.4、Handler Looper and Thread

由于我不是很熟悉java,也不是专业的android app开发工程师,所以关于这一小节的理解可能会有错误,如有小伙伴看到欢迎指出。以下是我对Thread、Handler、Looper的理解:

  • 每个 Activity 启动时都会自动开启一个线程,这个线程中应该执行了Looper.loop方法(我猜的),所有和 Activity 相关的事件均由这个 Looper 来做消息分发处理,这个线程也被称为 UI 线程;
  • 为什么一个线程 Thread 只能有一个 Looper 呢?因为 Looper.loop 是一个死循环,Thread.run 执行了这个方法当然就不能再去执行其他的内容了;
  • 为什么有的时候发消息用 Runnable,有的时候却用 Message 呢?我的理解是这样:用 Message 是让线程根据 Message.what 让 Handler 执行对应的操作,有的时候我们并不一定需要让Handler执行,工作可以直接在 Looper 中完成,这时候就用 Runnable;
  • 网上会有很多资料来讲主线程向子线程中发消息,子线程向主线程中发送消息,我觉得都没有理解到 Looper Handler 这块内容的本质。我的理解是这样,向某个线程发送消息,就是要将消息发到指定的 Looper 中,我们在创建 Handler 时会传入一个 Looper,我们利用对应线程的 Handler 就可以很轻松将 Message/Runnable 发送到指定线程中执行;当然我们也可用 Message.sendToTarget 将自身送到指定的 Looper;
  • HandlerThread 和 Thread 的区别在于前者在创建的时候会自动创建一个 Looper,而后者需要我们手动执行 Looper.prepare 以及 Looper.loop;
  • 网上会有很多资料来讲Handler的内存泄漏,这点我不是很能理解,Activity结束时为什么不去清理 Looper 中 MessageQueue 的内容呢?查看源码可以发现,我们可以在Activity结束时,在onDestory中调用Handler .removeCallbacksAndMessages 清除 MessageQueue 中由该 Handler 发送的内容;如果子线程中含有Looper,那么调用 Looper.quit 或者 Looper.quitSafely 可以安全退出子线程,同时可以调用 Thread.join 等待线程结束;如果用的是 HandlerThread ,我们可以调用 HanderThread.quitHanderThread.quitSafely 退出线程,这等同于调用 Looper.quit。按照我的理解,做到以上几点,内存泄露应该就不会发生了;
  • 以上内容的关键点在于退出 Activity 时能够打断 Run 函数,如果是UI线程我们不能主动打断,只能把 Handler 发出的消息清除;如果是子线程,我们可以通过打断 Looper 从而中断 Run 函数;

这里来看 MediaPlayer.java 中给我门提供的示例:

这里创建了一个 HandlerThread,来执行 addTrack 任务,任务执行完成后调用 Looper.quit退出线程。

        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
        thread.start();
        Handler handler = new Handler(thread.getLooper());
        handler.post(new Runnable() {
        	...
     	    public void run() {
                int res = addTrack();
                if (mEventHandler != null) {
                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
                    mEventHandler.sendMessage(m);
                }
                thread.getLooper().quitSafely();
            }
        });

还有另外一个示例,MediaPlayer的创建过程中会创建一个EventHandler,reset 时会调用 Handler.removeCallbacksAndMessages 来清除 MessageQueue 中由 EventHandler 发送的消息。如果 Handler 用的主线程 Looper,那么主线程可以安全退出;如果用的子线程 Looper,还需要调用该线程的 quit 方法打断 loop。

	public MediaPlayer() {
		....
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }
    }
    
    public void reset() {
    		...
            if (mEventHandler != null) {
            mEventHandler.removeCallbacksAndMessages(null);
        }
    }

如需更深入了解 Handler Looper and Thread 机制可以查看源码,也可以查看之前的 native AHandler ALooper 机制,原理大致是相同的 。


3、MediaPlayer Api分析

这一节主要是了解 MediaPlayer有什么api,我这里将api进行了罗列分组,并且贴出了他们的功能,至于他们要怎么用,有什么注意点,与生命周期相关的内容会在下一篇内容中了解。

首先是播放控制类api,这类api用于播放参数设定,以及Player生命周期的管理:

num methods Func
1 setDataSource 设置数据源
2 prepare 准备
3 prepareAsync 准备
4 start 开始播放
5 stop 停止播放
6 pause 暂停播放
7 release 释放当前播放器持有的资源
8 reset 重置播放器
9 finalize
10 setPlaybackParams 设置播放参数,例如倍速、Audio mode
11 setSyncParams 设置Avsync mode,有4种sync模式
12 seekTo 定位,有4种seek mode
13 setDisplay 设置 SurfaceHolder
14 setSurface 设置 Surface
15 setVideoScalingMode 设置缩放模式
16 setAudioStreamType 设置音频流类型
17 invoke 调用指定函数,no public,不支持App使用
18 setParameter 设定参数,no public,不支持App使用
19 setVolume 设置音量
20 setAudioSessionId 设置AudioSessionId
21 selectTrack 指定播放的track或者是切换当前播放的track

以下是参数获取类api,用他们可以获取到播放状态、播放参数等信息:

num methods Func
1 getVideoWidth 获取宽度
2 getVideoHeight 获取高度
3 isPlaying 是否正在播放
4 getPlaybackParams 获取播放参数
5 getSyncParams 获取Avsync参数,里面包含有帧率等信息
6 getTimestamp 获取当前播放时间戳
7 getCurrentPosition 获取当前播放时间,单位是msec,getTimestamp是基于这个方法的
8 getDuration 获取视频时长
9 getMetadata 获取当前播放流的信息,no public,不支持app使用,包含 bitrate、mine、codectype等信息
10 notifyAt 设置pts更新的频率
11 getAudioSessionId 获取AudioSessionId
12 getTrackInfo 获取当前Track的媒体格式
13 getSelectedTrack 获取当前选择的track

下面两个api用于循环播放或者是快速播放:

num methods Func
1 setNextMediaPlayer 设置下一个要播放的MediaPlayer,自动播放
2 setLooping 设置循环播放

以下类和方法用于回调事件的上抛与处理:

num class/function Func
1 EventHandler framework回调事件的处理
2 postEventFromNative native callback to framework

以方法用于将回调事件进一步上抛给app层,app做相应动作:

num class Func
1 OnPreparedListener prepareAsync完成,搭配start使用
2 OnCompletionListener 当前码流播放完成
3 OnBufferingUpdateListener 缓冲进度更新
4 OnSeekCompleteListener seek完成
5 OnVideoSizeChangedListener 视频的宽高发生变化,搭配 getVideoWidth 和 getVideoHeight使用
6 OnErrorListener 错误事件回调
7 OnTimedTextListener
8 OnTimedMetaDataAvailableListener
9 OnInfoListener 播放器信息回调
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 13 - Media框架(2)- Demo App与MediaPlayer Api了解 的相关文章

  • 如何清除所有WebView存储的信息?

    我有一个 Android 浏览器 我可以选择清除缓存 存储 cookie 等 代码如下所示 webView clearCache true webView clearFormData webView clearHistory webView
  • 使用workmanager时Firestore脱机持久性错误

    我正在使用一个WorkManger定期从我的中检索信息Firestore当应用程序处于后台和前台时的数据库 此信息用于根据状态更新 UI 因此不同的状态会添加或删除 UI 的不同部分 第一次运行时效果很好 但是 一旦应用程序处于后台并且Wo
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • 计数物体和更好的填充孔的方法

    我是 OpenCV 新手 正在尝试计算物体的数量在图像中 我在使用 MATLAB 图像处理工具箱之前已经完成了此操作 并在 OpenCV Android 中也采用了相同的方法 第一步是将图像转换为灰度 然后对其进行阈值计算 然后计算斑点的数
  • 当文本输入聚焦在 React Native for Android 的底部工作表上时,视图移出屏幕

    我正在使用图书馆 https github com osdnk react native reanimated bottom sheet https github com osdnk react native reanimated bott
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • 原色(有时)变得透明

    我正在使用最新的 SDK 版本 API 21 和支持库 21 0 2 进行开发 并且在尝试实施新的材料设计指南时遇到了麻烦 材料设计说我需要有我的primary color and my accent color并将它们应用到我的应用程序上
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何使用 IF 检查 TextView 可见性

    我有一个 onCheckedChangeListener 来根据选择的单选按钮显示文本视图 我有 1 个疑问和 1 个难题 想知道是否有人可以帮助我 问题 您能否将单选组默认检查值设置为 否 单选按钮 以便一开始就不会检查任何内容 问题 如
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 尝试在 ubuntu 中编译 android 内核时出错

    我正在尝试从源代码编译 Android 内核 并且我已经下载了所有正确的软件包来执行此操作 但由于某种原因我收到此错误 arm linux androideabi gcc error unrecognized command line op
  • 错误:在根项目“projectName”中找不到项目“app”

    我有一个在 Eclipse 中开发的旧应用程序 现在尝试将其迁移到 Android Studio 我更新了库并遵循了基本步骤 现在 我收到此错误 Error Project app not found in root project pro
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 一次显示两条Toast消息?

    我希望在一个位置显示一条 Toast 消息 并在另一位置同时显示另一条 Toast 消息 多个 Toast 消息似乎总是按顺序排队和显示 是否可以同时显示两条消息 是否有一种解决方法至少可以提供这种外观并且不涉及扰乱活动布局 Edit 看来
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL
  • 强制 Listview 不重复使用视图(复选框)

    我做了一个定制Listview 没有覆盖getView 方法 Listview 中的每个项目都具有以下布局 联系布局 xml

随机推荐

  • VS Code 配合 WSL 搭建 C/C++ 开发环境

    WSL 真香 最近在看 TCP IP网络编程 韩国人写的 讲解了 Windows 和 Linux 平台下的网络编程 才看了四章 感觉通俗易懂 值得一读 出版社网站上提供了源码 平时主要使用 Windows 为了看本书切换到 Linux 感觉
  • 盘点JAVA中比较常见的数据类型的 取值空间大小(让我们来干了这杯爪洼岛咖啡)

    JAVA作为一门面向对象的编程语言 吸收了C 等编程语言的优 点的同时 也展现了它独有的强大一面 列如可移植性可跨平台 性与及兼容性等特征 吸引了无数程序猿为其着迷 话不多说接下来今天我来带大家了解JAVA这门编程语言 中常用的数据类型的相
  • 深度学习------pytorch,CNN:实现mnist,cifar10数据集

    1 torch实现mnist数据集 1 1 cnn卷积 用全连接层写 实现mnist数据集分类 import torch from torch autograd import Variable import numpy as np from
  • How do Functional, Structural, and Behavioral Models Work Together to Describe a Whole System?

    原文链接 https brogramo com how do functional structural and behavioral models work together to describe a whole system As a
  • 机器学习、数据挖掘和统计模式识别学习(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 机器学习是让计算机在没有明确编程的情况下采取行动的科学 在过去的十年中 机器学习为我们提供了自动驾驶汽车 实用的语音识别 有效的网络搜索以及对人类基因组的理解大大提
  • postgresql-使用pg_dump导出表、pg_store导入表

    pg dump 是一个用于备份PostgreSQL数据库的实用工具 即使当前数据库正在使用 也能够生成一致性的备份 且不会阻塞其他用户访问数据库 包括读 写 pg restore 从一个归档中恢复一个由 pg dump 创建的 Postgr
  • 航空航天专业词汇(待补全)

    航空航天专业词汇 英文 中文 aborted rejected abandoned take off 中断起飞 above cloud 在云上 access flap 接口盖 acceleration 加速促进 actuating jack
  • html type=hidden 属性,input 属性及类型有哪些(type=text/button/hidden)

    input 从字面意就可以看出专门用来给用户输入文字的 当然也包括选择文件 它不具体表示某一类元素 如文本框 text 要使它具体表示一类元素必须加类型指明 如表示文本框加 type text type 也是 input 众多属性中最重要的
  • spring通过文件属性注入bean和基于xml的bean的自动装配以及spring-eel表达式的使用加代码合集

    前言 本章是spring基于XML 配置bean系类中第7篇讲解spring通过文件属性注入bean和基于xml的bean的自动装配以及spring eel表达式的使用加代码合集 个人主页 尘觉主页 个人简介 大家好 我是尘觉 希望我的文章
  • c语言 打空心菱形

    没错 如图所示 我们要整一个这样的菱形 写的挺麻烦的 代码如下 我是一半一半写的 要n 5 先写上半部分的代码 那么它是咋写出来的呢 本题可以完全用for语句写 但我选择了用for和if语句相结合的方式 i是代表的横 j代表的是列 所以它最
  • nginx相关漏洞处理:CVE-2016-2183、CVE-2022-41741、CVE-2022-41742

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 漏洞内容 二 现状 三 centos7安装openssl11 四 升级nginx到1 24 0 1 下载nginx 2 编译安装nginx 3 配置ngi
  • 2022数学建模美赛E题详细思路获取

    已更新 公众号 千千小屋grow 数据在文后链接 背景 正如我们所知 气候变化对生命构成了巨大的威胁 为了减轻气候变化的影响 我们需要采取严厉的行动 以减少大气中的温室气体的数量 仅仅是减少温室气体的排放是不够的 我们需要努力增加通过生物圈
  • log4j日志在java控制台输出,简单实用

    log4j日志在java控制台输出 简单实用 1 log4j输出有2中方式 第一种是将日志信息保存在一个文本当中 第二种是输出到控制台中 下面介绍第二种方式 2 在控制台输出log4j日志信息 是开发项目中常用的也是比不可少的也是必须会的一
  • 微信小程序中slider实现拾色器功能

    微信小程序中slider实现拾色器功能 思路 效果图 体验 代码 效果体验 思路 画板中要实现颜色选择功能 几经周折 效果还可以 整个思路就是 1 利用线性过渡实现slider背景渲染 2 获取slider滑块value值 3 计算该val
  • Markdown公式编辑学习笔记

    一 公式使用参考 1 如何插入公式 行中公式 放在文中与其它文字混编 可以用如下方法表示 数学公式 独立公式可以用如下方法表示 数学公式 自动编号的公式可以用如下方法表示 若需要手动编号 参见大括号和行标的使用 begin equation
  • 再看中国互联网web2.0百强名单

    无意中翻看到一篇我在三年多前写的文章 我看中国互联网web2 0百强名单 读来颇有感概 2005 2006那两年 正是WEB2 0概念轰轰烈烈的时候 大大小小的新网站层出不穷 博客 视频 交友 评点 社区 聚合 不管自己的网站的UGC比例多
  • bootstrap table 表格支持shirt 多选_bootstrap-table 表格行内编辑实现

    这篇文章向大家介绍一下如何使用bootstrap table插件实现表格的行内编辑功能 我的web前端学习交流群点击进入1045267283 欢迎加入 先放一张效果图 应用场景 之前的项目也是采用bootstrap table 添加和修改数
  • 牛客——子序列(组合数学)

    子序列 题目描述 给定一个小写字母字符串 T T T 求有多少长度为 m m m的小写字母字符串 S
  • 端口相关知识总结

    端口相关知识总结 80是服务器上的一个软件 服务器软件 端口是软件的代号 3306是MySQL的端口 1521是Oracle的端口 80是外部服务器的通用端口 京东也是 不写也可以访问 80端口可以省略 文件下载端口 FTP 都是21 FT
  • Android 13 - Media框架(2)- Demo App与MediaPlayer Api了解

    尝试用MediaPlayer写了一个播放demo 实现了网络流和本地流的播放 由于本人对app开发一窍不通 所以demo中很多内容是边查资料边写的 写的也比较杂乱 能够帮助理解api就行 这一节主要会记录demo开发中学到的内容 以及了解M