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.
As you discovered,
MediaBrowserServiceCompat
is already a bound service - you cannot and should not overrideonBind()
.Instead, you must connect to your
MediaBrowserServiceCompat
with aMediaBrowserCompat
as per the documentation. Once connected, you can trigger custom methods, likedoMagic
by:MediaControllerCompat
from yourMediaBrowserCompat
instance, following the documentationsendCommand
, passing in acommand
String which uniquely identifies your command (say,doMagic
), any parameters you wish to pass to the method, and aResultReceiver
if you want a return value.MediaSessionCompat.Callback
registered with yourMediaBrowserServiceCompat
, override onCommand() and handle the command (say, by callingdoMagic
).An example of this approach was offered in this blog post
You can try this solution (for a quick fix, not recommend):