如何在Media3 ExoPlayer播放过程中更新通知标题/描述?
解决Media3 ExoPlayer动态更新通知标题/描述的方案
核心思路
要同时兼容API 33以下的自定义通知和Media3 Session系统通知,核心是通过更新ExoPlayer当前播放MediaItem的MediaMetadata,让通知提供者自动读取最新元数据完成刷新。无需分别处理两种通知体系,统一通过元数据更新实现同步。
具体实现步骤
1. 自定义MediaNotification.Provider(适配API 33以下)
在PlaybackService中实现自定义通知提供者,确保每次构建通知时都从当前播放项的实时元数据中读取标题和描述:
public class PlaybackService extends MediaSessionService { private ExoPlayer player; private CustomNotificationProvider notificationProvider; private MediaSession mediaSession; @Override public void onCreate() { super.onCreate(); // 初始化ExoPlayer player = new ExoPlayer.Builder(this).build(); // 初始化自定义通知提供者 notificationProvider = new CustomNotificationProvider(this); setMediaNotificationProvider(notificationProvider); // 初始化MediaSession并关联播放器 mediaSession = new MediaSession.Builder(this, player).build(); setSession(mediaSession); } // 自定义通知提供者:每次构建通知时读取最新元数据 private static class CustomNotificationProvider implements MediaNotification.Provider { private final Context context; public CustomNotificationProvider(Context context) { this.context = context; } @Override public MediaNotification createNotification(MediaSession mediaSession, ImmutableList<CommandButton> customButtons, MediaNotification.ActionFactory actionFactory) { Player player = mediaSession.getPlayer(); MediaMetadata currentMetadata = player.getCurrentMediaItem().mediaMetadata; // 读取最新的标题和描述 String title = currentMetadata.title != null ? currentMetadata.title.toString() : "默认标题"; String description = currentMetadata.subtitle != null ? currentMetadata.subtitle.toString() : "默认描述"; // 构建基础通知(可自行添加播放控制按钮、渠道配置等) NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "PLAYBACK_CHANNEL") .setSmallIcon(R.drawable.ic_play_notification) .setContentTitle(title) .setContentText(description) .setStyle(new androidx.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.getSessionToken())) .setPriority(NotificationCompat.PRIORITY_DEFAULT); return new MediaNotification(1, builder.build()); } @Override public boolean shouldCreateNotification(Player player) { return player.getPlaybackState() != Player.STATE_IDLE; } } }
2. 在进度回调中更新元数据并触发刷新
在MainActivity的进度回调里,替换当前播放项的MediaMetadata,通过ExoPlayer和MediaSession同步变化,自动触发通知更新:
private void onPlayerProgressChanged(long current_playback_time) { if(current_playback_time >= something) { // 自定义触发条件 Player player = mediaSession.getPlayer(); int currentItemIndex = player.getCurrentMediaItemIndex(); MediaItem currentItem = player.getCurrentMediaItem(); if(currentItem == null) return; // 基于旧元数据构建新的元数据(仅更新需要修改的字段) MediaMetadata updatedMetadata = new MediaMetadata.Builder(currentItem.mediaMetadata) .setTitle("更新后的播放标题") .setSubtitle("更新后的播放描述") .build(); // 创建替换用的新MediaItem MediaItem updatedItem = new MediaItem.Builder(currentItem) .setMediaMetadata(updatedMetadata) .build(); // 更新ExoPlayer中的媒体项,并通知MediaSession变化 player.replaceMediaItem(currentItemIndex, updatedItem); player.notifyMediaItemChanged(currentItemIndex); } }
3. 关键注意事项
- 自动同步通知:API 33及以上的系统通知会通过MediaSession自动感知元数据变化刷新;API 33以下的自定义通知,会在元数据更新后由MediaSession触发
createNotification方法重新构建,无需手动调用通知刷新。 - 性能优化:进度回调触发频繁,建议设置合理的更新阈值(如仅在特定时间点或状态变化时更新),避免不必要的性能消耗。
- 空值处理:更新前要判断当前播放项是否为空,避免空指针异常。
内容的提问来源于stack exchange,提问作者Amr SubZero
相关产品推荐
相关产品推荐

