如何无需新建实例,更新PlayerNotificationManager的音频播放通知信息
问题分析
你的核心问题在于每次歌曲切换时都重新创建了整个PlayerNotificationManager实例,这完全没必要——ExoPlayer的PlayerNotificationManager设计就是用来长期复用的,重复创建不仅浪费系统资源,还可能导致通知闪烁、状态不一致等问题。
解决方案:复用PlayerNotificationManager实例
我们只需要初始化一次PlayerNotificationManager,然后在歌曲信息更新时,动态刷新通知内容即可。具体步骤如下:
- 将
PlayerNotificationManager定义为类成员变量,确保全局唯一 - 自定义
MediaDescriptionAdapter,让它能动态读取当前的歌曲标题和艺术家信息 - 在
onNewStreamTitle回调中,更新歌曲信息并触发通知刷新
修改后的完整代码示例
首先,在你的Service/Activity中添加类成员变量:
private PlayerNotificationManager mPlayerNotificationManager; private String currentSongTitle; // 存储当前歌曲名 private String currentArtist; // 存储当前艺术家
然后,拆分通知逻辑为初始化和内容更新两个方法:
// 初始化通知(仅调用一次,比如播放器准备完成时) void initExoPlayerNotification(Context context, SimpleExoPlayer exoPlayer) { if (mPlayerNotificationManager != null) { return; // 已初始化过,直接返回 } mPlayerNotificationManager = PlayerNotificationManager.createWithNotificationChannel( context, "PRIMARY_CHANNEL_ID", R.string.plaza, NOTIFICATION_ID, new PlayerNotificationManager.MediaDescriptionAdapter() { @Override public String getCurrentContentTitle(Player player) { return currentArtist != null ? currentArtist : "未知艺术家"; } @Nullable @Override public PendingIntent createCurrentContentIntent(Player player) { Intent intent = new Intent(service, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); return PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } @Override public String getCurrentContentText(Player player) { return currentSongTitle != null ? currentSongTitle : "未知歌曲"; } @Nullable @Override public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) { return BitmapFactory.decodeResource(service.getResources(), R.drawable.largeicon); } @Nullable @Override public String getCurrentSubText(Player player) { return null; } } ); // 通知配置仅需设置一次 mPlayerNotificationManager.setUseNavigationActions(false); mPlayerNotificationManager.setFastForwardIncrementMs(0); mPlayerNotificationManager.setRewindIncrementMs(0); mPlayerNotificationManager.setColorized(true); mPlayerNotificationManager.setColor(0xFFBDBDBD); mPlayerNotificationManager.setUseChronometer(true); mPlayerNotificationManager.setOngoing(true); mPlayerNotificationManager.setPriority(NotificationCompat.PRIORITY_MAX); mPlayerNotificationManager.setUsePlayPauseActions(true); mPlayerNotificationManager.setSmallIcon(R.drawable.smallwidth); mPlayerNotificationManager.setNotificationListener(new PlayerNotificationManager.NotificationListener() { @Override public void onNotificationStarted(int notificationId, Notification notification) { service.startForeground(notificationId, notification); } @Override public void onNotificationCancelled(int notificationId) { service.stopSelf(); cancelNotify(); } }); mPlayerNotificationManager.setPlayer(exoPlayer); } // 更新通知内容(歌曲切换时调用) void updateNotificationContent(String streamTitle) { // 解析歌曲名和艺术家,修复原代码的索引错误问题 try { currentSongTitle = StringUtils.substringBefore(streamTitle, " - "); currentArtist = StringUtils.substringAfter(streamTitle, " - "); } catch (Exception e) { int dashIndex = streamTitle.indexOf(" - "); if (dashIndex != -1) { currentSongTitle = streamTitle.substring(0, dashIndex); currentArtist = streamTitle.substring(dashIndex + 3); // 跳过" - "分隔符 } else { currentSongTitle = streamTitle; currentArtist = "未知艺术家"; } } // 触发通知刷新,让PlayerNotificationManager重新读取最新元数据 if (mPlayerNotificationManager != null) { mPlayerNotificationManager.incrementPlaybackState(); // 也可以直接调用 notify() 强制刷新 // mPlayerNotificationManager.notify(); } }
最后修改元数据监听回调,不再重建通知:
OnNewMetadataListener listener = new OnNewMetadataListener() { @Override public void onNewHeaders(String stringUri, List<String> name, List<String> desc, List<String> br, List<String> genre, List<String> info) { } @Override public void onNewStreamTitle(String stringUri, final String streamTitle) { MainActivity.songinfo.setText(streamTitle); // 只更新通知内容,不重建整个通知实例 updateNotificationContent(streamTitle); } }; // 在播放器初始化完成后调用一次通知初始化 initExoPlayerNotification(getApplicationContext(), exoPlayer); AudiostreamMetadataManager.getInstance() .setUri(uri) .setOnNewMetadataListener(listener) .setUserAgent(UserAgent.WINDOWS_MEDIA_PLAYER) .start();
关键优化点说明
- 复用核心实例:避免重复创建
PlayerNotificationManager,减少系统资源消耗,同时保证通知状态稳定无闪烁。 - 动态元数据读取:通过类成员变量存储最新歌曲信息,
MediaDescriptionAdapter在需要时自动读取最新值,替代原代码中用final变量固定死的逻辑。 - 容错逻辑修复:原代码的异常处理存在索引越界风险,现在优化了分隔符解析逻辑,确保解析失败时不会崩溃。
内容的提问来源于stack exchange,提问作者user7954210
相关产品推荐
相关产品推荐

