How to access instance of MediaBrowserServiceCompat service?
P

2

6

I'm surprisingly struggling to get hold of the instance of a service which is derived from MediaBrowserServiceCompat.

For a typical service, to achieve that, a local binder is used

class MyService extends MediaBrowserServiceCompat {
  class MyBinder extends Binder {
    public MyService getService() {
      return MyService.this;
    }

  private final MyBinder binder = new MyBinder();

  @Override
  public IBinder onBind(Intent intent) {
    return binder;
  }

  public void doMagic() { // <-- How to call this from activity?
    // ...
  }
}

// At the activity, for example, this binder is retrieved through 
// `onServiceConnected()`, typecast to `MyBinder` and thus 
// `getService()` gets us the service instance.

However, this does not work for the service derived from MediaBrowserServiceCompat.

When I try to provide local binder, as shown above, service crashed since MediaBrowserServiceCompat expects its own custom binder with additional functionality. Here is the crash stacktrace

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
    at android.os.Binder.queryLocalInterface(Binder.java:254)
    at android.service.media.IMediaBrowserService$Stub.asInterface(IMediaBrowserService.java:31)
    at android.media.browse.MediaBrowser$MediaServiceConnection.onServiceConnected(MediaBrowser.java:793)
    at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1223)
    at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1240)
    at android.os.Handler.handleCallback(Handler.java:746)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5443)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

I tried wrapping the binder from MediaBrowserServiceCompat super class, like below, but still it wouldn't work.

class MyService extends MediaBrowserServiceCompat {
  class MyBinder extends Binder {
    public MyService getService() {
      return MyService.this;
    }

  private final WrappingBinder<MyService> binder;

  @Override
  public IBinder onBind(Intent intent) {
    if (binder == null) {
      binder = new WrappingBinder(super.onBind(intent));
    }

    return binder;
  }

  public void doMagic() { // <-- How to call this from activity or elsewhere?
    // ...
  }
}

So wondering what is the approach to follow to access the instance of MediaBrowserServiceCompat service?

To be clear, Playback functionality is working fine for me. The question is about how to get a reference to the service, so that I can make calls to my custom public methods on that service.

Perturbation answered 30/4, 2018 at 12:16 Comment(2)
MediaBrowserServiceCompat is a Service . To create one class MyService extends MediaBrowserServiceCompat Follow This. it may help .Selfcentered
I followed that. Playback functionality is working fine for me. The question is about how to get a reference to the service, so that I can make calls to my custom public methods on that service.Perturbation
V
15

As you discovered, MediaBrowserServiceCompat is already a bound service - you cannot and should not override onBind().

Instead, you must connect to your MediaBrowserServiceCompat with a MediaBrowserCompat as per the documentation. Once connected, you can trigger custom methods, like doMagic by:

  1. Create a MediaControllerCompat from your MediaBrowserCompat instance, following the documentation
  2. Call sendCommand, passing in a command String which uniquely identifies your command (say, doMagic), any parameters you wish to pass to the method, and a ResultReceiver if you want a return value.
  3. In the MediaSessionCompat.Callback registered with your MediaBrowserServiceCompat, override onCommand() and handle the command (say, by calling doMagic).

An example of this approach was offered in this blog post

Vacationist answered 30/4, 2018 at 16:25 Comment(3)
Dear ianhanniballake, how can I notify UI update from MediaBrowserServiceCompat, in my case, player file need download to local before play, how can I notify activity show/hide loading. ThanksDrusi
@hai - sounds like you should take a look at the EXTRA_DOWNLOAD_PROGRESS constant and it's related methods. You can also send custom actions from your service to all connected MediaBrowserCompat via the sendSessionEvent API on the MediaBrowserServiceCompatVacationist
Thank you so much, it's what I looking forDrusi
D
0

You can try this solution (for a quick fix, not recommend):

private final MyBinder myBinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
    if (intent.getBooleanExtra("is_binding", false)) {
        return myBinder;
    }
    return super.onBind(intent);
}

// Bind service in your activity:

Intent intent = new Intent(this, MyPlaybackService.class);
intent.putExtra("is_binding", true);

bindService(intent, this, Context.BIND_AUTO_CREATE);
Disavow answered 5/1, 2019 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.