移动开发

Android Media3 中的 MediaSession 框架

MediaSession 是构建媒体应用(尤其是那些需要在后台播放、响应媒体按钮、以及与其他应用和系统组件交互的应用)的核心组件。

1. 框架设计 (Framework Design)

Media3 中的 MediaSession 框架是 Jetpack Media3 库的一部分,它是在旧版 android.media.session.MediaSession (API 21+) 和 androidx.media.session.MediaSessionCompat 的基础上进行了现代化和简化的设计。其核心设计目标是:

  • 解耦与模块化: Media3 将媒体播放的各个方面(如 UI、播放逻辑、媒体资源管理)分离开来。MediaSession 主要负责声明应用的媒体播放状态接收来自外部的播放控制命令
  • 单一事实来源 (Single Source of Truth): MediaSession 作为应用媒体状态的中心枢纽。它向 Android 系统和其他应用广播当前的播放信息(元数据、播放状态、播放队列等),并接收来自它们的控制指令。
  • Player 接口的集成: Media3 的核心是 androidx.media3.common.Player 接口。MediaSession 通常与一个实现了 Player 接口的播放器实例(如 ExoPlayer)协同工作。Player 负责实际的媒体解码和渲染,而 MediaSession 则将 Player 的状态和控制暴露给外部。
  • 向后兼容性: 虽然 Media3 是新的库,但它在设计时考虑了与旧版 Android 系统和其他媒体应用的兼容性。它在底层仍然会利用系统提供的 MediaSession 机制。
  • 简化生命周期管理: Media3 旨在简化与 Android 组件生命周期(如 Service、Activity)的集成。
  • 易于测试: 模块化的设计使得对媒体逻辑进行单元测试和集成测试更加容易。

核心组件和概念:

  • MediaSession:
    • 核心职责:
      • 向系统和其他应用报告应用的媒体播放状态(正在播放什么、播放进度、可用的控制命令等)。
      • 接收来自系统(如媒体按钮、Google Assistant)、其他应用或蓝牙设备的播放控制命令。
      • 管理播放队列。
    • 关联对象: 通常与一个 Player 实例关联。它通过监听 Player 的事件来更新自身状态,并将外部命令转发给 Player
  • Player (例如 ExoPlayer):
    • 负责媒体内容的加载、解码、渲染和播放控制(播放、暂停、快进、快退等)。
    • MediaSession 并不直接处理媒体数据流,而是依赖 Player 来完成。
  • MediaSession.Callback:
    • 一个接口,允许应用自定义如何响应来自控制器(Controller)的媒体命令。例如,当用户按下“播放”按钮时,Callback 中的 onPlay() 方法会被调用。
    • 开发者可以实现此回调来拦截、修改或处理特定的播放命令,然后再(或不)将其委托给 Player
  • MediaController:
    • 其他应用或系统组件用来控制 MediaSession 的客户端。
    • 它可以发现正在运行的 MediaSession,获取其状态,并向其发送播放命令。
    • 在 Media3 中,你也可以在应用内部使用 MediaController 与你自己的 MediaSession 进行交互,例如从 Activity 控制后台播放服务中的 MediaSession
  • MediaSessionService:
    • 一个专门用于托管 MediaSessionPlayer 的 Android Service
    • 这是推荐的在后台运行媒体播放的方式,确保即使应用 UI 不可见,播放也能继续。
    • 它会自动处理服务的生命周期、前台服务管理(对于 Android O 及更高版本至关重要,以避免后台播放被终止)以及媒体按钮接收者的注册。
  • MediaLibraryService (可选,但推荐用于媒体浏览):
    • MediaSessionService 的一个子类,增加了媒体浏览功能。
    • 它允许客户端(如 Android Auto、Wear OS 或其他媒体浏览应用)查询和浏览你的应用提供的媒体内容库。
    • 通过实现 MediaLibrarySession.Callback 中的 onGetLibraryRoot(), onGetChildren(), onGetItem() 等方法来提供媒体库结构。
  • MediaNotificationManager / PlayerNotificationManager:
    • Media3 提供了工具来简化媒体播放通知的创建和管理。
    • 这些通知会显示当前播放的元数据、播放控件,并与 MediaSession 的状态同步。
    • PlayerNotificationManager(来自 ExoPlayer 旧版,但在 Media3 中仍可找到类似概念或通过 MediaSessionService 自动处理)负责将 Player 的状态转换成一个持续的通知。MediaSessionService 内部集成了通知管理。

数据流和交互模型:

  1. 初始化:
    • 应用创建一个 Player 实例 (如 ExoPlayer)。
    • 应用创建一个 MediaSession,并将 Player 实例与之关联。
    • 如果需要后台播放,MediaSessionPlayer 通常托管在 MediaSessionService 中。
  2. 状态广播:
    • Player 的状态发生变化(例如,开始播放、暂停、切换曲目、加载元数据),它会通知关联的 MediaSession
    • MediaSession 更新其内部状态,并通过 Android 系统的媒体子系统将这些状态(如 PlaybackStateCompat, MediaMetadataCompat)广播出去。
  3. 命令接收:
    • 系统或其他应用的 MediaController 可以发现此 MediaSession
    • 用户通过媒体按钮(耳机、蓝牙设备)、系统 UI(如通知栏、锁屏控件)或语音命令(如 Google Assistant)与媒体进行交互。
    • 这些交互被转换成媒体命令,发送到应用的 MediaSession
  4. 命令处理:
    • MediaSession 接收到命令。
    • 如果设置了 MediaSession.Callback,相应的回调方法会被调用。
    • 在回调方法中,应用可以决定如何处理该命令。通常,这些命令会被委托给关联的 Player 实例执行(例如,调用 player.play()player.pause())。
  5. UI 更新 (可选,应用内):
    • 如果应用的 UI (如 Activity 或 Fragment) 需要显示播放状态或控制播放,它也可以创建一个 MediaController 来连接到同一个 MediaSession(即使是在同一个应用内),从而接收状态更新并发送命令。

这种设计使得媒体播放逻辑与 UI 和系统交互清晰分离,提高了代码的可维护性和可测试性。

2. 框架使用 (Framework Usage)

使用 Media3 中的 MediaSession 框架通常涉及以下步骤:

步骤 1: 添加依赖

在你的 build.gradle (Module: app) 文件中添加 Media3 的相关依赖:

Gradle

dependencies {
    // 核心 Media3 库,包含 Player 接口, ExoPlayer, MediaSession 等
    implementation "androidx.media3:media3-session:1.3.1" // 使用最新版本
    implementation "androidx.media3:media3-exoplayer:1.3.1"
    implementation "androidx.media3:media3-ui:1.3.1" // 如果需要内置的 UI 组件

    // 如果需要 HLS, DASH, SmoothStreaming 支持,可以添加相应的 ExoPlayer 模块
    implementation "androidx.media3:media3-exoplayer-hls:1.3.1"
    implementation "androidx.media3:media3-exoplayer-dash:1.3.1"
}

请注意检查并使用最新的 Media3 版本。

步骤 2: 创建 Player 实例

通常使用 ExoPlayer

Java

// 在你的 Service 或 Activity 中
import androidx.media3.exoplayer.ExoPlayer;

Player player = new ExoPlayer.Builder(context).build();

步骤 3: 创建 MediaSession

Java

// 在你的 Service 或 Activity 中
import androidx.media3.session.MediaSession;

// 1. 创建 MediaSession
MediaSession mediaSession = new MediaSession.Builder(context, player)
        .setId("my_awesome_music_session") // 可选,但推荐用于调试
        // .setSessionActivity(pendingIntentToOpenActivity) // 用户点击通知时打开的 PendingIntent
        // .setCallback(new MyMediaSessionCallback()) // 可选,用于自定义命令处理
        .build();
  • context: 通常是 ApplicationContextService context。
  • player: 你在步骤 2 中创建的 Player 实例。
  • setId(): 为会话设置一个唯一的 ID,方便调试。
  • setSessionActivity(): 设置一个 PendingIntent,当用户从通知或其他地方选择你的会话时,会启动这个 Intent(通常是打开你的播放器 UI Activity)。
  • setCallback(): (可选但常用) 设置一个 MediaSession.Callback 来处理自定义命令或在命令执行前后执行额外逻辑。

步骤 4: (推荐) 使用 MediaSessionService 进行后台播放

这是管理后台播放、媒体按钮和通知的推荐方式。

  • 创建 MyMediaSessionService.java:

Java

import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.session.MediaSession;
import androidx.media3.session.MediaSessionService;

public class MyMediaSessionService extends MediaSessionService {

    private MediaSession mediaSession = null;
    private Player player = null;

    @Override
    public void onCreate() {
        super.onCreate();
        initializePlayerAndSession();
    }

    private void initializePlayerAndSession() {
        player = new ExoPlayer.Builder(this).build();
        // 设置音频属性,例如用途和内容类型,这对于音频焦点管理很重要
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
                .setUsage(C.USAGE_MEDIA)
                .build();
        player.setAudioAttributes(audioAttributes, true /* handleAudioFocus */); // true 表示让 ExoPlayer 自动处理音频焦点

        mediaSession = new MediaSession.Builder(this, player)
                .setCallback(new MyMediaSessionCallback()) // 可选的回调
                .build();
    }

    @Override
    public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
        // 返回 MediaSession 实例,允许客户端连接
        return mediaSession;
    }

    // (可选) 自定义回调
    private class MyMediaSessionCallback implements MediaSession.Callback {
        // 在这里重写需要自定义处理的命令,例如 onPlay, onPause, onSkipToNext 等
        // 例如:在播放前检查网络,或者记录分析数据
    }

    @Override
    public void onDestroy() {
        if (player != null) {
            player.release();
            player = null;
        }
        if (mediaSession != null) {
            mediaSession.release();
            mediaSession = null;
        }
        super.onDestroy();
    }
}
  • AndroidManifest.xml 中声明 Service:

XML

<service
    android:name=".MyMediaSessionService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

foregroundServiceType=”mediaPlayback” 对于 Android 9 (API 28) 及更高版本是必需的。

exported=”true” 允许其他应用连接到你的服务。

步骤 5: 管理 Player 和 MediaSession 的生命周期

  • 初始化: 在 Service.onCreate()Activity.onCreate() 中创建和设置 PlayerMediaSession
  • 释放资源: 在 Service.onDestroy()Activity.onDestroy() 中调用 player.release()mediaSession.release()。这非常重要,以避免资源泄漏。如果 MediaSessionPlayer 关联,通常释放 Player 会自动更新 MediaSession 的状态,但显式释放两者是好习惯。MediaSessionService 会在适当的时候帮助管理这些。

步骤 6: 加载和播放媒体

使用 Player 接口的方法来控制播放:

Java

// 假设 player 是你的 ExoPlayer 实例
import androidx.media3.common.MediaItem;

// 创建一个 MediaItem
MediaItem mediaItem = MediaItem.fromUri("YOUR_MEDIA_URI_HERE"); // 例如 http://, file://, asset://

// 将 MediaItem 添加到播放列表并准备播放
player.setMediaItem(mediaItem);
player.prepare(); // 异步准备

// 开始播放 (可以在准备完成后,或者用户请求时)
player.play(); // 或者 player.setPlayWhenReady(true);

// 其他控制:
// player.pause();
// player.seekTo(positionMs);
// player.setRepeatMode(Player.REPEAT_MODE_ONE / Player.REPEAT_MODE_ALL / Player.REPEAT_MODE_OFF);
// player.setShuffleModeEnabled(true/false);

步骤 7: (可选) 从 Activity/Fragment 控制 MediaSessionService

如果你的 MediaSession 托管在 MediaSessionService 中,你的 UI (Activity/Fragment) 可以使用 MediaController 来与之通信。

Java

// 在你的 Activity 或 Fragment 中
import androidx.media3.session.MediaController;
import androidx.media3.session.SessionToken;
import android.content.ComponentName;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.ExecutionException;

// ...

SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, MyMediaSessionService.class));

ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();

controllerFuture.addListener(
    () -> {
        try {
            MediaController mediaController = controllerFuture.get();
            // 现在你可以使用 mediaController 来控制播放和监听状态变化
            // 例如: mediaController.play(), mediaController.pause()
            // mediaController.addListener(new Player.Listener() { ... });
            // 在不需要时释放: mediaController.release();
        } catch (ExecutionException | InterruptedException e) {
            // 处理错误
        }
    },
    MoreExecutors.directExecutor() // 或者 ContextCompat.getMainExecutor(this)
);

// 记得在 Activity/Fragment 销毁时释放 controller
// private MediaController mediaController;
// @Override
// protected void onDestroy() {
//     if (mediaController != null) {
//         MediaController.releaseFuture(controllerFuture); // 或 mediaController.release() 如果已经获取
//     }
//     super.onDestroy();
// }

步骤 8: 处理通知

当你使用 MediaSessionService 时,它会自动为你处理媒体通知的创建和更新。通知会显示当前的媒体元数据和播放控件。你可以通过 MediaSessionService.setMediaNotificationProvider() 来自定义通知的外观和行为,或者直接让其使用默认提供者。

如果未使用 MediaSessionService,你可能需要使用 PlayerNotificationManager (来自 androidx.media3:media3-ui 包) 手动创建和管理通知,并将其与 MediaSession 同步。

3. 框架提供的自定义能力 (Customization Capabilities)

Media3 MediaSession 框架提供了广泛的自定义能力,允许开发者根据具体需求调整其行为:

  1. MediaSession.Callback:
    • 拦截和处理媒体命令: 这是最核心的自定义点。你可以重写 Callback 中的方法(如 onPlay, onPause, onSkipToNext, onSeekTo, onSetRating, onCustomCommand 等)来改变默认行为。
      • 示例:
        • onPlay() 中检查用户是否拥有播放权限。
        • onSkipToNext() 中实现自定义的下一曲目选择逻辑(例如,基于用户喜好推荐)。
        • 发送分析事件记录用户的播放行为。
        • 在实际执行播放前加载广告。
    • 自定义命令 (Custom Commands): 通过 onCustomCommand (发送方) 和 MediaSession.Callback.onCustomCommand (接收方),应用可以定义和处理标准媒体命令之外的自定义操作。例如,切换音效、添加到收藏夹、调整播放速度的特定档位等。
    • 修改播放队列: onAddMediaItems, onSetMediaItems, onSetShuffleModeEnabled, onSetRepeatMode 等回调允许你控制播放队列的修改方式。
  2. 自定义 Player 行为:
    • 由于 MediaSessionPlayer 接口解耦,你可以使用任何实现了 Player 接口的播放器。虽然 ExoPlayer 是最常用的,但理论上你可以实现自己的 Player
    • 对于 ExoPlayer 本身,它提供了大量的自定义选项:
      • 自定义 LoadControl 来改变缓冲策略。
      • 自定义 RenderersFactory 来使用自定义的音频/视频渲染器。
      • 添加 AnalyticsListener 来接收详细的播放事件。
      • 配置 DataSource.Factory 来从各种来源加载媒体(网络、本地文件、自定义服务器)。
      • 处理 DRM (数字版权管理)。
  3. 通知自定义 (MediaNotificationProvider):
    • 当使用 MediaSessionService 时,它使用一个 MediaNotificationProvider 来创建和更新媒体通知。
    • 你可以提供自己的 MediaNotificationProvider 实现来完全控制通知的外观和行为:
      • 自定义通知图标、颜色、布局(部分受系统限制)。
      • 自定义通知中的操作按钮(例如,添加“喜欢”、“不喜欢”按钮)。
      • 修改通知的优先级和渠道。
    • DefaultMediaNotificationProvider 本身也提供了一些构造函数参数来自定义常用选项,如通知图标。
  4. 媒体浏览 (MediaLibraryServiceMediaLibrarySession.Callback):
    • 如果你希望你的应用内容能被其他应用(如 Android Auto, Wear OS, Google Assistant)浏览和播放,你需要使用 MediaLibraryService
    • 通过实现 MediaLibrarySession.Callback 的方法,你可以定义你的媒体库结构:
      • onGetLibraryRoot(): 返回媒体库的根节点。
      • onGetChildren(): 返回指定父媒体项下的子媒体项列表(例如,专辑下的歌曲列表,播放列表中的曲目)。
      • onGetItem(): 返回单个媒体项的详细信息。
      • onSearch(): (如果支持) 实现搜索逻辑。
    • 这允许你以树状结构或自定义结构组织你的音乐、播客等内容。
  5. 广播自定义元数据和播放状态:
    • 你可以通过 Player.setMediaItems() 设置包含丰富元数据(标题、艺术家、专辑封面 URI、时长等)的 MediaItemMediaSession 会将这些信息广播出去。
    • 通过 MediaSession.setCustomLayout(),你可以为连接的控制器(如 Android Auto)提供一组自定义操作按钮的布局。
    • MediaSession.setSessionExtras() 允许你附加一个 Bundle 的额外数据到 MediaSession,供 MediaController 读取。
  6. 可用命令 (Available Commands):
    • MediaSession 维护一组当前可用的播放命令(Player.Commands)。例如,如果当前没有下一首歌曲,则 COMMAND_SEEK_TO_NEXT_MEDIA_ITEM 可能不可用。
    • 你可以通过 MediaSession.Builder.setAvailableCommandsProvider() 或在 MediaSession.Callback 中动态修改这些可用命令,以精确控制远程控制器可以执行哪些操作。
    • Player 本身也会根据其状态(例如,是否有可寻找的内容)更新其可用命令,MediaSession 会反映这些。
  7. 连接特定控制器 (MediaSession.Callback.onConnect):
    • 当一个新的 MediaController 尝试连接到你的 MediaSession 时,onConnect 回调会被调用。
    • 你可以在这里决定是否接受连接(例如,基于包名进行白名单/黑名单验证),或者为特定的控制器配置不同的可用命令或自定义布局。
  8. 错误处理和报告:
    • Player.Listener.onPlayerError 可以用来监听播放器错误。
    • 你可以在 MediaSession.Callback 中处理这些错误,例如向用户显示友好的错误消息,或者尝试恢复播放。

通过组合这些自定义点,开发者可以构建出功能丰富且高度定制化的媒体播放体验。

4. 开发音乐 App 会用到的框架能力 (Application in a Music App)

对于开发一款音乐 App,你会广泛地使用 Media3 MediaSession 框架的多种能力:

  1. 核心播放控制 (Player + MediaSession):
    • ExoPlayer: 用于实际的音乐文件(MP3, AAC, FLAC, Ogg Vorbis 等)的解码和播放,支持网络流(HTTP/HTTPS, HLS, DASH)、本地文件。
    • MediaSession:
      • ExoPlayer 实例关联,以声明播放状态(正在播放、暂停、缓冲、当前歌曲、进度)。
      • 接收来自系统(通知栏、锁屏、蓝牙耳机按钮、Android Auto、Wear OS、Google Assistant)的播放/暂停/上一首/下一首/快进/快退命令,并将它们转发给 ExoPlayer
  2. 后台播放 (MediaSessionService):
    • 至关重要: 音乐通常需要在应用 UI 不可见时继续播放。MediaSessionService 确保播放可以在后台可靠运行,并自动管理前台服务状态以防止被系统终止。
    • 它还会处理媒体按钮事件的接收。
  3. 媒体元数据和封面 (MediaItemMediaMetadata):
    • 为每首歌曲创建 MediaItem,并通过 MediaMetadata.Builder 设置丰富的元数据:
      • setTitle(): 歌曲名称
      • setArtist(): 艺术家
      • setAlbumTitle(): 专辑名称
      • setAlbumArtist(): 专辑艺术家
      • setArtworkUri() / setArtworkData(): 专辑封面(URI 或 byte array)
      • setTrackNumber(): 音轨号
      • setTotalTrackCount(): 专辑总音轨数
      • setReleaseDate(): 发行日期
      • setGenre(): 音乐流派
      • setUserRating() / setOverallRating(): 用户评分
      • setExtras(): 存储其他自定义信息,如歌词 URI、音质等。
    • MediaSession 会将这些元数据广播给系统,用于在通知、锁屏、蓝牙设备上显示。
  4. 播放队列管理 (Player 接口方法, MediaSession.Callback):
    • 使用 player.addMediaItem(s), player.removeMediaItem(s), player.moveMediaItem(s) 等方法管理播放队列。
    • 用户可能希望对播放列表进行排序、添加歌曲、移除歌曲。这些操作会更新 Player 的播放列表,MediaSession 会反映这些变化。
    • 实现 MediaSession.Callback 中的 onAddMediaItems, onSetMediaItems 等方法,可以让你在这些操作发生时执行额外逻辑(如保存播放列表状态)。
    • 支持随机播放 (player.setShuffleModeEnabled(true/false)) 和重复播放 (player.setRepeatMode(Player.REPEAT_MODE_OFF/ONE/ALL)).
  5. 媒体通知 (MediaSessionServicePlayerNotificationManager):
    • MediaSessionService 会自动创建和更新一个包含当前歌曲信息和播放控件的通知。
    • 自定义通知:
      • 通过 DefaultMediaNotificationProvider.Builder 或自定义 MediaNotificationProvider 来设置应用图标、通知颜色。
      • 添加自定义操作按钮,如“喜欢”、“添加到播放列表”、“查看歌词”等(通过 MediaSession.Callback.onCustomCommandMediaNotificationProvider.getActions())。
  6. 媒体浏览 (MediaLibraryServiceMediaLibrarySession.Callback):
    • 非常推荐: 允许用户通过 Android Auto、Wear OS、Google Assistant 或其他媒体浏览应用来浏览和播放你的音乐库。
    • 实现 MediaLibrarySession.Callback
      • onGetLibraryRoot(): 返回根目录(例如,”我的音乐库”)。
      • onGetChildren():
        • 返回不同分类的入口,如“专辑”、“艺术家”、“播放列表”、“流派”、“所有歌曲”。
        • 对于“专辑”节点,返回该专辑下的所有歌曲。
        • 对于“艺术家”节点,返回该艺术家的所有专辑或歌曲。
      • onGetItem(): 返回特定歌曲的 MediaItem(包含所有元数据)。
      • (可选) onSearch(): 实现音乐库内搜索功能。
    • 这使得你的音乐 App 能够很好地融入 Android 生态系统。
  7. 音频焦点管理:
    • ExoPlayer 可以通过 player.setAudioAttributes(audioAttributes, true /* handleAudioFocus */) 自动处理音频焦点。
    • 当其他应用请求音频焦点时(例如,导航应用开始播报方向),你的音乐播放会自动暂停或降低音量(ducking)。当焦点返回时,播放会自动恢复。
    • 正确处理音频焦点对于良好的用户体验至关重要。
  8. 媒体按钮响应 (耳机、蓝牙设备):
    • MediaSessionService 会自动注册一个媒体按钮接收器。当用户按下耳机或蓝牙设备上的播放/暂停/下一首/上一首按钮时,这些事件会被路由到你的 MediaSession,进而控制 ExoPlayer
  9. 锁屏控件:
    • MediaSession 处于活动状态并正在播放媒体时,Android 系统会在锁屏界面显示媒体控件(歌曲信息、封面、播放控制按钮)。这是由系统自动处理的,只要你的 MediaSession 正确发布了状态和元数据。
  10. 自定义命令和操作 (MediaSession.Callback.onCustomCommand):
    • “喜欢/不喜欢”歌曲: 发送自定义命令,在 Callback 中处理,更新歌曲的喜好状态,并可能更新 UI 和服务器数据。
    • 添加到播放列表: 自定义命令,在 Callback 中弹出对话框让用户选择播放列表,或直接添加到默认列表。
    • 调整播放速度/音高: 虽然 ExoPlayer 支持 setPlaybackParameters,但你可能希望通过自定义命令提供预设的速度选项。
    • 查看歌词: 自定义命令,触发在 UI 中显示歌词的逻辑。
    • 下载歌曲: 自定义命令,触发歌曲下载逻辑。
  11. 错误处理和报告:
    • 监听 Player.Listener.onPlayerError 来捕获播放错误(如网络问题、文件损坏、解码错误)。
    • MediaSession.CallbackPlayer.Listener 中处理这些错误,例如:
      • 向用户显示友好的错误消息。
      • 尝试重新连接或播放下一首歌曲。
      • 记录错误以供分析。
  12. 与 UI (Activity/Fragment) 的交互 (MediaController):
    • UI 组件使用 MediaController 连接到 MediaSessionService 中的 MediaSession
    • 监听状态: 监听 Player.Listener 事件(通过 MediaController)来更新 UI 上的播放进度条、歌曲信息、播放/暂停按钮状态、封面等。
    • 发送命令: UI 上的按钮(播放、暂停、下一首、拖动进度条)通过 MediaControllerMediaSession 发送命令。
  13. 最近播放/播放历史:
    • MediaSession.CallbackonPlayPlayer.Listener.onMediaItemTransition 中记录播放的歌曲,用于实现“最近播放”功能。
  14. Android Auto / Wear OS 集成:
    • 通过正确实现 MediaLibraryService,你的音乐应用可以无缝地在 Android Auto 和 Wear OS 设备上提供浏览和播放体验。
    • MediaSession 还会将播放状态和元数据同步到这些设备。

通过有效地利用这些 Media3 MediaSession 框架的能力,你可以构建一个功能强大、用户体验良好且与 Android 生态系统深度集成的音乐应用。记住,MediaSessionServiceMediaLibraryService (如果需要浏览) 是现代音乐应用的关键组件。

留言

您的邮箱地址不会被公开。 必填项已用 * 标注