TL;DR:我已成功创建并(通过订阅)将活动耦合到媒体浏览器服务。此媒体浏览器服务可以继续运行并在后台播放音乐。我希望能够在某个阶段刷新内容,无论是在应用程序再次进入前台时还是在 SwipeRefreshLayout 事件期间。
我想实现以下功能:
- 启动 MediaBrowserServiceCompat 服务。
- 从活动中,连接并订阅媒体浏览器服务。
- 允许该服务在应用关闭时继续运行和播放音乐。
- 在稍后阶段,或在 SwipeRefreshLayout 事件中,重新连接并订阅服务以获取新鲜内容。
我收到的问题是在 MediaBrowserService 中(在创建订阅后)您只能从 onLoadChildren() 方法调用一次 sendResult() ,因此下次尝试使用相同的根订阅媒体浏览器服务时,第二次调用 sendResult() 时会出现以下异常:
E/UncaughtException: java.lang.IllegalStateException: sendResult() called when either sendResult() or sendError() had already been called for: MEDIA_ID_ROOT
at android.support.v4.media.MediaBrowserServiceCompat$Result.sendResult(MediaBrowserServiceCompat.java:602)
at com.roostermornings.android.service.MediaService.loadChildrenImpl(MediaService.kt:422)
at com.roostermornings.android.service.MediaService.access$loadChildrenImpl(MediaService.kt:50)
at com.roostermornings.android.service.MediaService$onLoadChildren$1$onSyncFinished$playerEventListener$1.onPlayerStateChanged(MediaService.kt:376)
at com.google.android.exoplayer2.ExoPlayerImpl.handleEvent(ExoPlayerImpl.java:422)
at com.google.android.exoplayer2.ExoPlayerImpl$1.handleMessage(ExoPlayerImpl.java:103)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:5665)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:822)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:712)
我调用以下方法来连接和断开媒体浏览器(同样,在第一次连接时一切运行顺利,但在第二次连接时,我不确定如何通过订阅刷新内容):
override fun onStart() {
super.onStart()
mMediaBrowser = MediaBrowserCompat(this, ComponentName(this, MediaService::class.java), connectionCallback, null)
if (!mMediaBrowser.isConnected)
mMediaBrowser.connect()
}
override fun onPause() {
super.onPause()
//Unsubscribe and unregister MediaControllerCompat callbacks
MediaControllerCompat.getMediaController(this@DiscoverFragmentActivity)?.unregisterCallback(mediaControllerCallback)
if (mMediaBrowser.isConnected) {
mMediaBrowser.unsubscribe(mMediaBrowser.root, subscriptionCallback)
mMediaBrowser.disconnect()
}
}
我在 onPause() 而不是 onDestroy() 中取消订阅并断开连接,以便即使活动保留在后台堆栈上也会重新创建订阅。
分别在活动和服务中用于滑动刷新的实际方法:
活动
if (mMediaBrowser.isConnected)
mMediaController?.sendCommand(MediaService.Companion.CustomCommand.REFRESH.toString(), null, null)
服务
inner class MediaPlaybackPreparer : MediaSessionConnector.PlaybackPreparer {
...
override fun onCommand(command: String?, extras: Bundle?, cb: ResultReceiver?) {
when(command) {
// Refresh media browser content and send result to subscribers
CustomCommand.REFRESH.toString() -> {
notifyChildrenChanged(MEDIA_ID_ROOT)
}
}
}}
其他研究:
我参考了 Github 上的 Google Samples 代码,以及...
- https://github.com/googlesamples/android-MediaBrowserService
- https://github.com/moondroid/UniversalMusicPlayer
在创建媒体浏览器服务并且活动至少订阅一次后,上述存储库似乎都没有处理刷新内容的问题 - 我想避免重新启动服务,以便音乐可以在后台继续播放。
可能的相关问题:
- MediaBrowser.subscribe 在我从活动 2(6.0.1 Android)返回活动 1 后不起作用——对当前问题没有影响