一、框架

1. MediaSession (媒体会话)
• 角色: 核心枢纽和状态机。它是整个媒体播放控制的核心。
• 作用:
bash
封装播放状态: 持有当前播放状态(如播放/暂停、当前播放位置、播放速度、播放队列、当前媒体项元数据等)。
暴露控制接口: 通过 setCallback() 设置一个 MediaSession.Callback。这个回调定义了如何处理来自外部的控制命令(如 onPlay(), onPause(),
onSkipToNext(), onSeekTo() 等)。应用的后台播放逻辑主要实现在这里。
分发状态更新: 当播放状态发生变化(如开始播放、暂停、切歌、进度更新)时,MediaSession 会主动通知所有连接到它的 MediaController。
提供令牌 (Token): 生成一个 MediaSession.Token。这个 Token 是 MediaSession的唯一标识符和安全凭证,用于前台组件(通过 MediaBrowser)连接到后台服务并获取 MediaController。
• 位置: 通常由后台服务(MediaBrowserService)创建并持有。
• 关键点: 它不直接处理媒体播放,而是定义接口和保存状态,具体的播放动作由 MediaSession.Callback 的实现者(你的播放逻辑)完成。
2. MediaBrowserService (媒体浏览器服务)
• 角色: 后台服务的基类。它是长期运行在后台(通常在一个独立的进程)的服务,负责管理媒体内容库、播放逻辑以及与前台 UI 的连接。
• 作用:
bash
生命周期管理: 作为 Android Service,它可以在 UI 不可见时(如应用退到后台、锁屏)继续运行,保证播放不中断。
托管 MediaSession: 创建并持有 MediaSession 实例,实现其 Callback 中的播放控制逻辑。
管理内容库: 实现 onLoadChildren() 等方法,向连接的客户端(MediaBrowser)提供媒体内容的结构(如专辑列表、歌曲列表)。
连接点: 提供 onGetRoot() 方法,验证请求连接的客户端(MediaBrowser)是否有权限,并返回一个 BrowserRoot 对象(通常包含 MediaSession 的 Token)。这是前台连接后台的入口。
管理客户端连接: 维护连接到它的 MediaBrowser 客户端列表。
• 位置: 后台服务,继承自 Service。
• 关键点: 它是后台播放逻辑的容器和连接桥梁。它创建 MediaSession 并实现其核心播放逻辑。
3. MediaBrowser (媒体浏览器)
• 角色: 前台 UI 的连接器。由前台组件(如 Activity、Fragment)创建和使用。
• 作用:
bash
连接到 MediaBrowserService: 使用 MediaBrowserService 的组件名(或通过 MediaSession.Token)发起连接请求。
获取会话令牌: 连接成功后,通过 getSessionToken() 方法获取到 MediaBrowserService 所持有的 MediaSession 的 Token。
浏览媒体内容: 使用 subscribe() 方法订阅媒体内容树(如"所有歌曲"、"按艺术家")的更新,并通过 MediaBrowser.SubscriptionCallback 接收内容(MediaItem 列表)。使用 unsubscribe() 取消订阅。
断开连接: 在 UI 销毁时断开与服务的连接。
• 位置: 前台 UI 组件(Activity/Fragment)。
• 关键点: 它主要负责建立连接和获取内容结构。它本身不直接控制播放。获取到 MediaSession.Token 后,它的主要任务就完成了(用于创建 MediaController)。
4. MediaController (媒体控制器)
• 角色: 前台 UI 的控制代理和状态接收器。
• 作用:
bash
创建: 前台 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.关系和工作流程
- 后台启动: 你的应用启动后台服务(继承自 MediaBrowserService)。该服务在 onCreate() 中创建 MediaSession,设置其 Callback(实现播放逻辑),并可能开始准备播放。
- 前台启动: 用户打开应用 UI(Activity/Fragment)。
- 连接: UI 创建 MediaBrowser 对象,使用 MediaBrowserService 的组件名调用 connect() 尝试连接。
- 验证与连接: MediaBrowserService 的 onGetRoot() 被调用,验证客户端权限并返回 BrowserRoot(包含 MediaSession.Token)。连接成功。
- 获取控制器: UI 的 MediaBrowser.ConnectionCallback.onConnected() 被调用。在这里,UI 通过 MediaBrowser.getSessionToken() 获取 MediaSession.Token,并用它创建 MediaController。
- 浏览内容 (可选): UI 可以使用 MediaBrowser.subscribe() 请求媒体内容结构(如显示歌曲列表)。
- 控制播放: 当用户点击 UI 上的播放按钮时,UI 调用 MediaController.getTransportControls().play()。
- 命令路由: MediaController 将 play() 命令发送给后台的 MediaSession。
- 执行命令: MediaSession 调用其 Callback.onPlay() 方法。你在这里实现的后台播放逻辑开始执行(例如,开始播放音乐)。
- 状态更新: 播放开始后,后台逻辑(在 Callback.onPlay() 中)更新 MediaSession 的状态(例如,设置播放状态为 PlaybackState.STATE_PLAYING)。
- 状态分发: MediaSession 自动将新的播放状态广播给所有连接的 MediaController。
- UI 更新: UI 的 MediaController 收到状态更新,触发其注册的 MediaController.Callback.onPlaybackStateChanged()。UI 在这里更新界面(如将按钮图标改为暂停图标,更新进度条)。
- 断开: 当 UI 销毁时,它调用 MediaController.unregisterCallback() 和 MediaBrowser.disconnect() 进行清理。
注意点
• MediaSession: 核心状态和控制接口。定义"能做什么"(Callback)和"当前状态是什么"。
• MediaBrowserService: 后台服务的基类。托管 MediaSession,实现播放逻辑,管理内容库,处理客户端连接。
• MediaBrowser: 前台连接器。负责连接到 MediaBrowserService 并获取 MediaSession.Token(用于创建 MediaController)和浏览内容。
• MediaController: 前台代理。利用 MediaSession.Token 与后台 MediaSession 通信,发送控制命令并接收状态更新,驱动 UI 变化。