TL;DR:アクティビティを作成し、(サブスクリプションを介して) メディア ブラウザー サービスに結合することに成功しました。このメディア ブラウザ サービスは、実行を継続し、バックグラウンドで音楽を再生できます。アプリが再びフォアグラウンドになったとき、または SwipeRefreshLayout イベント中に、ある段階でコンテンツを更新できるようにしたいと考えています。
実装したい次の機能があります。
- MediaBrowserServiceCompat サービスを開始します。
- アクティビティから、メディア ブラウザー サービスに接続してサブスクライブします。
- アプリを閉じている間も、サービスの実行と音楽の再生を継続できるようにします。
- 後の段階で、または SwipeRefreshLayout イベントで、サービスに再接続してサブスクライブし、新しいコンテンツを取得します。
私が受け取っている問題は、MediaBrowserService 内で (サブスクリプションが作成された後)、 onLoadChildren() メソッドから sendResult() を 1 回しか呼び出せないため、次に同じルートを使用してメディア ブラウザ サービスにサブスクライブしようとするときです。の場合、sendResult() が 2 回目に呼び出されると、次の例外が発生します。
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)
次のメソッドを呼び出して、メディア ブラウザーに接続および切断します (ここでも、最初の接続ではすべてがスムーズに実行されますが、2 番目の接続では、サブスクリプションを介してコンテンツを更新する方法がわかりません)。
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()
}
}
アクティビティがバックスタックに保持されている場合でもサブスクリプションが再作成されるように、onDestroy() の代わりに onPause() でサブスクリプションを解除して切断します。
アクティビティとサービスのそれぞれで、スワイプの更新に使用される実際の方法:
アクティビティ
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
上記のレポはどちらも、メディア ブラウザ サービスが作成され、アクティビティが少なくとも 1 回サブスクライブされた後にコンテンツを更新する問題を処理していないようです。
関連する可能性のある問題: