本部分介绍了如何将媒体播放器应用拆分为媒体控制器(适用于界面)和媒体会话(适用于实际播放器)。其中介绍了两种媒体应用架构:适用于音频应用的客户端/服务器设计以及适用于视频播放器的单 activity 设计。此外,还介绍了如何让媒体应用响应硬件控件以及与使用音频输出流的其他应用协作。
播放器和界面
播放音频或视频的多媒体应用通常由两部分组成:
- 播放器,用于接收数字媒体并将其渲染为视频和/或音频
- 界面,带有用于运行播放器并显示播放器状态(可选)的传输控件
在 Android 中,您可以从零开始构建自己的播放器,也可以从以下选项中进行选择:
- MediaPlayer 类提供准系统播放器的基本功能,支持最常见的音频/视频格式和数据源。
- ExoPlayer 是一个基于
MediaCodec
和AudioTrack
等较低级别的媒体框架组件构建的开源库。ExoPlayer 支持 DASH 等高性能功能,这些功能在MediaPlayer
中不可用。您可以自定义 ExoPlayer 代码,从而轻松添加新组件。ExoPlayer 只能用于 Android 4.1 及更高版本。
媒体会话和媒体控制器
虽然界面和播放器采用的 API 可能各不相同,但是对所有媒体播放器应用来说,这两部分之间的交互的性质都基本相同。Android 框架定义了两个类(媒体会话和媒体控制器),它们为构建媒体播放器应用提供了一个完善的结构。
媒体会话和媒体控制器通过以下方式相互通信:使用与标准播放器操作(播放、暂停、停止等)相对应的预定义回调,以及用于定义应用独有的特殊行为的可扩展自定义调用。
媒体会话
媒体会话负责与播放器的所有通信。它会对应用的其余部分隐藏播放器的 API。系统只能从控制播放器的媒体会话中调用播放器。
会话会维护播放器状态(播放/暂停)的表示形式以及播放内容的相关信息。会话可以接收来自一个或多个媒体控制器的回调。这样,应用的界面以及搭载 Wear OS 和 Android Auto 的配套设备就可以控制您的播放器。响应回调的逻辑必须保持一致。无论哪个客户端应用发起了回调,对 MediaSession
回调的响应都应该相同。
媒体控制器
媒体控制器会隔离您的界面。您的界面代码只与媒体控制器(而非播放器本身)通信。媒体控制器会将传输控制操作转换为对媒体会话的回调。每当会话状态发生变化时,它也会接收来自媒体会话的回调。这提供了一种自动更新关联界面的机制。媒体控制器一次只能连接到一个媒体会话。
当您使用媒体控制器和媒体会话时,您可以在运行时部署不同的接口和/或播放器。您可以根据运行应用的设备的功能单独更改该应用的外观和/或性能。
视频应用与音频应用的差异
播放视频时,您的眼睛和耳朵都需要参与互动。播放音频时,您需要聆听,但您也可以同时使用其他应用。每种使用情形都有不同的设计。
视频应用
视频应用需要一个窗口来查看内容。出于这个原因,视频应用通常作为单个 Android Activity 来实现。呈现视频的屏幕是 Activity 的一部分。
音频应用
音频播放器并不总是需要显示其界面。一旦开始播放音频,播放器就可以作为后台任务运行。用户可以切换到其他应用,同时继续聆听。
要在 Android 中实现此设计,您可以使用两个组件构建音频应用:对界面使用 Activity,对播放器使用服务。如果用户切换到其他应用,该服务可以在后台运行。通过将音频应用的两个部分分解为单独的组件,每个组件都可以更高效地独立运行。与播放器(可能会在没有界面的情况下运行很长时间)不同,界面通常是短时的。
支持库提供了两个类来实现此客户端/服务器方法:MediaBrowserService
和 MediaBrowser
。服务组件作为包含媒体会话及其播放器的 MediaBrowserService
的子类来实现。包含界面和媒体控制器的 activity 应包含一个 MediaBrowser
,后者与 MediaBrowserService
进行通信。
使用 MediaBrowserService
可以让配套设备(如 Android Auto 和 Wear)轻松发现您的应用、连接到您的应用、浏览内容以及控制播放,而根本无需访问应用的界面 activity。事实上,可以有多个应用同时连接到同一 MediaBrowserService
,每个应用都有自己的 MediaController
。提供 MediaBrowserService
的应用应该能够处理多个并发连接。
媒体应用和 Android 音频基础架构
设计良好的媒体应用应该能够与其他播放音频的应用“和谐共存”。它应准备好与使用音频的其他应用共用手机并相互配合。它还应该对设备上的硬件控件做出响应。
所有这些行为都在控制音频输出中进行了介绍。
media-compat 库
media-compat 库包含可帮助您构建音频和视频应用的类。这些类与搭载 Android 2.3(API 级别 9)及更高版本的设备兼容。它们还可与其他 Android 功能配合使用,以打造舒适亲切的 Android 体验。
媒体会话和媒体控制器的建议实现方式是 MediaSessionCompat
和 MediaControllerCompat
类,它们在 media-compat 支持库中定义。它们取代了 Android 5.0(API 级别 21)中引入的早期版本的 MediaSession
和 MediaController
类。compat 类提供相同的功能,但可让您更轻松地开发应用,因为您只需写入一个 API。该库通过将媒体会话方法转换为更低版本平台上的等效方法(可用时)来保证向后兼容性。
如果您已经有使用旧类的实际应用,我们建议更新到 compat 类。使用兼容型版本时,您可以从 RemoteControlClient
中移除对 registerMediaButtonReceiver()
的所有调用以及所有方法。
衡量性能
在 Android 8.0(API 级别 26)及更高版本中,getMetrics()
方法可用于某些媒体类。它会返回一个包含配置和性能信息的 PersistableBundle
对象(表示为属性和值的对应关系)。可以为这些媒体类定义 getMetrics()
方法:
MediaPlayer.getMetrics()
MediaRecorder.getMetrics()
MediaCodec.getMetrics()
MediaExtractor.getMetrics()
系统会为每个实例分别收集相关指标,并在实例的整个生命周期内保留这些指标。如果没有任何可用指标,则该方法会返回 null。返回的实际指标取决于类。