news 2026/7/14 18:15:53

android 媒体之 MediaSession

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
android 媒体之 MediaSession

一、框架

1. MediaSession (媒体会话)

• 角色: 核心枢纽和状态机。它是整个媒体播放控制的核心。

• 作用:

封装播放状态: 持有当前播放状态(如播放/暂停、当前播放位置、播放速度、播放队列、当前媒体项元数据等)。 暴露控制接口: 通过 setCallback()设置一个 MediaSession.Callback。这个回调定义了如何处理来自外部的控制命令(如 onPlay(), onPause(), onSkipToNext(), onSeekTo()等)。应用的后台播放逻辑主要实现在这里。 分发状态更新: 当播放状态发生变化(如开始播放、暂停、切歌、进度更新)时,MediaSession 会主动通知所有连接到它的 MediaController。 提供令牌(Token): 生成一个 MediaSession.Token。这个 Token 是 MediaSession的唯一标识符和安全凭证,用于前台组件(通过 MediaBrowser)连接到后台服务并获取 MediaController。

• 位置: 通常由后台服务(MediaBrowserService)创建并持有。

• 关键点: 它不直接处理媒体播放,而是定义接口和保存状态,具体的播放动作由 MediaSession.Callback 的实现者(你的播放逻辑)完成。

2. MediaBrowserService (媒体浏览器服务)

• 角色: 后台服务的基类。它是长期运行在后台(通常在一个独立的进程)的服务,负责管理媒体内容库、播放逻辑以及与前台 UI 的连接。

• 作用:

生命周期管理: 作为 Android Service,它可以在 UI 不可见时(如应用退到后台、锁屏)继续运行,保证播放不中断。 托管 MediaSession: 创建并持有 MediaSession 实例,实现其 Callback 中的播放控制逻辑。 管理内容库: 实现 onLoadChildren()等方法,向连接的客户端(MediaBrowser)提供媒体内容的结构(如专辑列表、歌曲列表)。 连接点: 提供 onGetRoot()方法,验证请求连接的客户端(MediaBrowser)是否有权限,并返回一个 BrowserRoot 对象(通常包含 MediaSession 的 Token)。这是前台连接后台的入口。 管理客户端连接: 维护连接到它的 MediaBrowser 客户端列表。

• 位置: 后台服务,继承自 Service。

• 关键点: 它是后台播放逻辑的容器和连接桥梁。它创建 MediaSession 并实现其核心播放逻辑。

3. MediaBrowser (媒体浏览器)

• 角色: 前台 UI 的连接器。由前台组件(如 Activity、Fragment)创建和使用。

• 作用:

连接到 MediaBrowserService: 使用 MediaBrowserService 的组件名(或通过 MediaSession.Token)发起连接请求。 获取会话令牌: 连接成功后,通过 getSessionToken()方法获取到 MediaBrowserService 所持有的 MediaSession 的 Token。 浏览媒体内容: 使用 subscribe()方法订阅媒体内容树(如“所有歌曲”、“按艺术家”)的更新,并通过 MediaBrowser.SubscriptionCallback 接收内容(MediaItem 列表)。使用 unsubscribe()取消订阅。 断开连接: 在 UI 销毁时断开与服务的连接。

• 位置: 前台 UI 组件(Activity/Fragment)。

• 关键点: 它主要负责建立连接和获取内容结构。它本身不直接控制播放。获取到 MediaSession.Token 后,它的主要任务就完成了(用于创建 MediaController)。

4. MediaController (媒体控制器)

• 角色: 前台 UI 的控制代理和状态接收器。

• 作用:

创建: 前台 UI 组件使用 MediaBrowser 连接成功后获取到的 MediaSession.Token,通过 MediaControllerCompat.getMediaController()或 MediaControllerCompat 的构造函数创建 MediaController。 发送控制命令: 提供方法(如 getTransportControls().play(), pause(), skipToNext(), seekTo())让 UI 发送播放控制命令。这些命令最终会被路由到后台 MediaSession 的 Callback 中执行。 获取当前状态: 提供方法(如 getPlaybackState(), getMetadata())让 UI 查询当前的播放状态和媒体元数据。 接收状态更新: 通过注册 MediaController.Callback,UI 可以监听 MediaSession 的状态变化(如播放状态改变、元数据更新、队列变化)。当后台状态变化时,MediaSession 会通知所有关联的 MediaController,这些 MediaController 再回调其注册的 Callback 通知 UI 更新。 与 MediaSession 交互: 它是前台 UI 与后台 MediaSession 交互的主要通道。

• 位置: 前台 UI 组件(Activity/Fragment),通常与 MediaBrowser 在同一组件中使用。

• 关键点: 它是 UI 控制播放和获取状态更新的主要工具。它通过 MediaSession.Token 与后台的 MediaSession 建立联系。

5.关系和工作流程

  1. 后台启动: 你的应用启动后台服务(继承自 MediaBrowserService)。该服务在 onCreate() 中创建 MediaSession,设置其 Callback(实现播放逻辑),并可能开始准备播放。
  2. 前台启动: 用户打开应用 UI(Activity/Fragment)。
  3. 连接: UI 创建 MediaBrowser 对象,使用 MediaBrowserService 的组件名调用 connect() 尝试连接。
  4. 验证与连接: MediaBrowserService 的 onGetRoot() 被调用,验证客户端权限并返回 BrowserRoot(包含 MediaSession.Token)。连接成功。
  5. 获取控制器: UI 的 MediaBrowser.ConnectionCallback.onConnected() 被调用。在这里,UI 通过 MediaBrowser.getSessionToken() 获取 MediaSession.Token,并用它创建 MediaController。
  6. 浏览内容 (可选): UI 可以使用 MediaBrowser.subscribe() 请求媒体内容结构(如显示歌曲列表)。
  7. 控制播放: 当用户点击 UI 上的播放按钮时,UI 调用 MediaController.getTransportControls().play()。
  8. 命令路由: MediaController 将 play() 命令发送给后台的 MediaSession。
  9. 执行命令: MediaSession 调用其 Callback.onPlay() 方法。你在这里实现的后台播放逻辑开始执行(例如,开始播放音乐)。
  10. 状态更新: 播放开始后,后台逻辑(在 Callback.onPlay() 中)更新 MediaSession 的状态(例如,设置播放状态为 PlaybackState.STATE_PLAYING)。
  11. 状态分发: MediaSession 自动将新的播放状态广播给所有连接的 MediaController。
  12. UI 更新: UI 的 MediaController 收到状态更新,触发其注册的 MediaController.Callback.onPlaybackStateChanged()。UI 在这里更新界面(如将按钮图标改为暂停图标,更新进度条)。
  13. 断开: 当 UI 销毁时,它调用 MediaController.unregisterCallback() 和 MediaBrowser.disconnect() 进行清理。

注意点

• MediaSession: 核心状态和控制接口。定义“能做什么”(Callback)和“当前状态是什么”。

• MediaBrowserService: 后台服务的基类。托管 MediaSession,实现播放逻辑,管理内容库,处理客户端连接。

• MediaBrowser: 前台连接器。负责连接到 MediaBrowserService 并获取 MediaSession.Token(用于创建 MediaController)和浏览内容。

• MediaController: 前台代理。利用 MediaSession.Token 与后台 MediaSession 通信,发送控制命令并接收状态更新,驱动 UI 变化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 7:18:39

时序数据选型、存储模型与选型

时序数据选型、存储模型与选型 一、时序数据的特征与挑战 时间戳驱动:数据天然带有时间维度,典型场景包括监控指标、传感器采集、交易日志。高吞吐写入:数据持续产生,要求数据库具备批量写入与乱序处理能力。查询模式特殊&#xf…

作者头像 李华
网站建设 2026/7/14 3:49:22

基于微信小程序的家政服务系统

博主介绍:java高级开发,从事互联网行业六年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的设计程序开发,开发过上千套设计程序,没有什么华丽的语言,只有实…

作者头像 李华
网站建设 2026/7/13 13:04:29

MindSpore高效训练指南:从数据流水线到混合精度实战

在昇腾(Ascend)NPU上进行深度学习模型训练时,我们经常会遇到GPU转NPU的代码迁移问题,或者发现算力虽然强劲,但训练速度受限于IO或显存。作为一名在昇腾生态摸爬滚打的开发者,今天我想分享几个基于MindSpore…

作者头像 李华
网站建设 2026/7/14 12:20:30

两阶段鲁棒优化在主动配电网动态无功优化中的实践

两阶段鲁棒优化的主动配电网动态无功优化 关键词:两阶段鲁棒优化,CCG算法,储能 仿真算例采用33节点,采用matlabyalmipcplex编写,两阶段模型采用CCG算法求解。 模型中一阶段变量主要包括01变量和无功优化变量&#xff0…

作者头像 李华
网站建设 2026/7/14 18:00:15

探索 DSPLLC 开关电源模块设计的宝藏世界

DSPLLC开关电源模块设计资料DSP数字LLC电源源代码原理图软件学习,包含磁件设计、软件设计报告、硬件设计报告、硬件原理、主功率计算书、LLC环路设计、仿真、BOM、使用说明,调试波形等全面且详细的全套资料最近在研究电源相关的技术,发现了一…

作者头像 李华
网站建设 2026/7/12 21:21:41

基于推荐算法的校园电子图书听书系统

Spring Boot基于推荐算法的校园电子图书听书系统是一个专为校园师生设计的数字化阅读平台。以下是对该系统的详细介绍: 一、系统背景与目的 随着信息技术的不断发展,数字化阅读已经成为校园阅读的新趋势。为了满足校园师生对电子图书和听书资源的需求&am…

作者头像 李华