使用Android Media3库调用MediaController添加MediaItem报空指针错误
问题根因
Media3中MediaItem的localConfiguration属于进程本地专有数据,不会通过Binder跨进程序列化传输。你在Activity端通过MediaController调用添加MediaItem时,数据传到MediaSessionService所在进程后localConfiguration会被自动置空,因此DefaultMediaSourceFactory做非空校验时直接抛出空指针异常。
解决方案
方案1:重写MediaSession.Callback重构MediaItem(通用推荐)
这是官方适配跨进程场景的标准实现方式,步骤如下:
- 你在
MediaSessionService中初始化MediaSession时,设置自定义的MediaSession.Callback回调,重写onAddMediaItems方法 - Activity端构建
MediaItem时,将播放所需的必要信息(如资源uri、mediaId、自定义参数等)存入MediaItem的mediaId、requestMetadata或mediaMetadata字段,这些字段官方保证会跨进程序列化传递 - Service端的
onAddMediaItems回调收到Activity传递过来的MediaItem列表后,遍历每个条目,取出存储的参数重新构建完整的、带localConfiguration的MediaItem返回给播放器即可
示例代码(Kotlin):
class CustomMediaSessionCallback : MediaSession.Callback { override fun onAddMediaItems( mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList<MediaItem> ): List<MediaItem> { // 重新构建MediaItem,自动生成localConfiguration return mediaItems.map { remoteItem -> MediaItem.Builder() // 这里可以根据自己的业务逻辑取参数,比如从remoteItem.requestMetadata.mediaUri取资源地址 .setUri(remoteItem.requestMetadata.mediaUri) .setMediaId(remoteItem.mediaId) .setMediaMetadata(remoteItem.mediaMetadata) .build() } } } // 初始化MediaSession时绑定回调 val mediaSession = MediaSession.Builder(context, exoPlayer) .setCallback(CustomMediaSessionCallback()) .build()
方案2:同进程部署(仅适合单进程场景)
如果你的业务不需要让MediaSessionService运行在独立进程,可以直接在Manifest中给MediaSessionService指定进程和主进程一致,不存在跨进程传输的情况下localConfiguration不会丢失,即可直接调用MediaController.addMediaItem:
<service android:name=".YourMediaSessionService" android:process=":your_main_process_name" <!-- 保持和主进程相同 --> android:exported="true"> <intent-filter> <action android:name="androidx.media3.session.MediaSessionService" /> </intent-filter> </service>
方案3:通过自定义指令传递参数
如果需要更灵活的控制,也可以在Activity端调用MediaController.sendCustomCommand方法,将需要添加的资源列表参数打包到Bundle中传递到Service端,Service端收到指令后自行构建MediaItem并添加到播放器。
注意事项
永远不要依赖localConfiguration跨进程传递任何数据,所有需要跨进程传输的播放参数都需要存到Media3官方明确支持序列化的字段中,避免出现数据丢失问题。
内容的提问来源于stack exchange,提问作者RE_OVO
相关产品推荐
相关产品推荐

