androidx / androidx/media

MediaController.Builder and MediaController#release correct implementation

Open
#501 0 comments 1 reaction 1 assignee View on GitHub

@marcbaechinger is already working on this.

Since Jul 7, 2023.

needs triage question
Dominant language
Java
Stars
3k
Forks
955
Avg merge
12d 14h
Merged PRs (30d)
2

Description

Media 3 version: 1.1.0

I've been having the problem with the "dead" notification that throws a Context.startForegroundService() did not then call Service.startForeground() exception or android.os.DeadObjectException when the notification is derived from the PlaybackState.

I know there are several issues created about this topic, I've read a lot of them and I'm sure I've missed some, but after some testing I found out that my problem is with how I create and release the MediaController and I would like to use this issue to know more about why my implementation doesn't work.


In my app sometimes the issue appears when:

  1. Open app and play some media
  2. Pause the playback
  3. Remove the app from recents

When the issue happens, MediaNotificationManager#onDisconnect is never called after my controller.release(), so I think this missing call is what keeps the notification in a bad state.

Since the :demo-session app from media3 doesn't have the same problem with its controller, I modified PlayerActivity to copy some of the aspects of my implementation and recreate the issue in the demo app.

Change 1: Delay call to controller.release()

In my app, if I modify my Activity to initialize the controller, play something, and then immediately release it (without waiting for onStop), the problem never appears.

Since immediately releasing the controller fixes the problem, I tried the opposite to cause it.

Modify PlayerActivity#onStop and add a delay before the call to releaseController().

override fun onStop() {
    super.onStop()
    playerView.player = null
    Thread.sleep(5_000) // <---
    releaseController()
}

Note: My app does some work before calling release() and my guess is that sometimes it takes longer than others. That could explain the inconsistency of the stale notification.

This change is not enough. The notification will disappear 5 seconds after the app is removed from recents (no issue).

Change 2: initializeController context

If I use the application/applicationContext when creating the MediaController, I'm able to recreate the issue, but it never happens when activity (this) is used.

Modify PlayerActivity#initializeController()

private fun initializeController() {
    val tokenContext = applicationContext // || application
    controllerFuture =
            MediaController.Builder(
                    tokenContext,
                    SessionToken(tokenContext, ComponentName(tokenContext, PlaybackService::class.java))
            )
                    .buildAsync()
    controllerFuture.addListener({ setController() }, MoreExecutors.directExecutor())
}

At some point I modified my app to use dependency injection to inject the SessionToken and the Hilt module in charge uses the applicationContext to provide it. I don't know much about SessionToken or ComponentName and maybe this is the wrong way to do it.


After implementing those changes, I can recreate the issue in :demo-session with the same steps from above. The only difference is that, when removing the app from recents, we need to do it within the sleep time of 5 seconds. If we go to the recents list (onStop is called) and wait more than 5 seconds before dismissing the app, the issue won't appear.

At this point, since I know what's causing it, I could just work around it but I'd really like to know why it happened. Why can't I release the controller after doing some work cleaning the UI? Why does it matter the type of context I use to initialize the controller?

Sorry If this doesn't make any sense. I've tried so many combinations that I wouldn't be surprised if I ended up with the wrong conclusions. Thanks!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.