ServiceConnectionLeaked in Android-ThrowExceptions

Exception or error:

I’m attempting to use a Service in Android for some basic database operations, but for some reason I’m getting an Activity has leaked ServiceConnection error. I’ll post the full Logcat readout at the bottom.

I have to use the same service in multiple activities, so I’ve created a Superclass to handle all of the service tasks. It looks like this:

private MyInterface child;

public void onCreate(Bundle savedInstanceState, MyInterface child){
    super.onCreate(savedInstanceState);

    doBindService();
}

public void onResume(){
    super.onResume();

    doBindService();
}

protected void onPause(){
    super.onPause();

    doUnbindService();
}

private boolean bound;
private boolean binding;

ServiceConnection Connection = new ServiceConnection(){

    //called when the service is connected
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(LOGTAG, "Bound to Service");
        bound = true;
        binding = false;
        toServiceMessenger = new Messenger(service);
        while(!commandsForService.isEmpty()){
            sendToService(commandsForService.poll());
        }
    }

    //called when the service is disconnected
    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(LOGTAG, "Unboud from Service");
        bound = false;
        binding = false;
        toServiceMessenger = null;
    }
};

private boolean doBindService(){
    Log.d(LOGTAG, "Attempting to Bind to Service");
    if(!bound && !binding){
        binding = true;
        bindService(new Intent(this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE);
    }
    return bound;
}

private void doUnbindService(){
    Log.d(LOGTAG, "Attempting to Unbind from Service");
    if(bound && !binding){
        binding = true;
        unbindService(Connection);
    }
}

public void sendToService(Message msg){
    if(bound){
        sendMessageToService(msg);
    }
    else{
        commandsForService.add(msg);
    }
}

private void sendMessageToService(Message msg){
    if(bound){
        msg.replyTo = fromServiceMessenger;
        try {
            toServiceMessenger.send(msg);
        } catch (RemoteException e) {
            Log.d(LOGTAG, "RemoteException communicating with service");
        }
    }
    else{
        Log.d(LOGTAG, "Error: toServiceMessenger null while bound");
    }
}

The idea is that the child activity will never need to worry about being connected to the service or not, the Superclass should take care of getting data the service and back to the child.

The Logcat points doBindService() in onCreate() –> bindService(new Intent(this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE); as the line causing the error. However, the service only leaks after the activity has been running and visible for longer than 15 seconds, so I don’t think that onCreate() should have been called.

Here’s the Logcat:

09-02 09:25:40.635: E/ActivityThread(5963): Activity childActivity has leaked ServiceConnection superClass$1@42cb1b70 that was originally bound here
09-02 09:25:40.635: E/ActivityThread(5963): android.app.ServiceConnectionLeaked: Activity childActivity has leaked ServiceConnection superClass$1@42cb1b70 that was originally bound here
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1055)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:949)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ContextImpl.bindService(ContextImpl.java:1472)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ContextImpl.bindService(ContextImpl.java:1464)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.content.ContextWrapper.bindService(ContextWrapper.java:394)
09-02 09:25:40.635: E/ActivityThread(5963):     at superClass.doBindService(FetchActivity.java:253)
09-02 09:25:40.635: E/ActivityThread(5963):     at superClass.onCreate(FetchActivity.java:61)
09-02 09:25:40.635: E/ActivityThread(5963):     at childActivity.onCreate(Showcase_Activity.java:37)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.Activity.performCreate(Activity.java:5066)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ActivityThread.access$600(ActivityThread.java:151)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.os.Looper.loop(Looper.java:155)
09-02 09:25:40.635: E/ActivityThread(5963):     at android.app.ActivityThread.main(ActivityThread.java:5493)
09-02 09:25:40.635: E/ActivityThread(5963):     at java.lang.reflect.Method.invokeNative(Native Method)
09-02 09:25:40.635: E/ActivityThread(5963):     at java.lang.reflect.Method.invoke(Method.java:511)
09-02 09:25:40.635: E/ActivityThread(5963):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
09-02 09:25:40.635: E/ActivityThread(5963):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795)
09-02 09:25:40.635: E/ActivityThread(5963):     at dalvik.system.NativeStart.main(Native Method)

Any help will be greatly appreciated.

How to solve:

As you call the doBindService() in the onCreate(), you should add the do UnbindService() in onDestroy().

It works for me.

###

You’re calling doBindService() in both onCreate() and onResume(), trying calling it just in onResume() to match your call to doUnbindService() in onPause()

###

You need to use the good reference for the Activity
getActivity() return the current one, and you need to unbind on the one which did the bind

here’s how I fixed the problem :

private Activity mActivity;
    @Override
    public void onStart() {
        super.onStart();
        if (!mBound) {
            startService();
            mActivity = getActivity();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mBound && mActivity != null) {
            mActivity.unbindService(mServiceConnection);
            mActivity = null;
        }
    }

###

You are getting this error because service which you bind with activity is not stopped when that activity destroyed. So due this your service is still exist in memory and consuming resources, which is doing nothing.

To solve this problem call doBindService() in onCreate() and doUnbindService() in onDestroy()

###

This issue is limited to Android SDKs prior to Android O, API level 26. In Android O the following function to launch foreground services was introduced ContextCompat.startForegroundService(...) as opposed to context.startService(...). The older APIs do not handle the foreground lifecycle, thus the need to call context?.unbindService(serviceConnection) in onDestroy(...).

The new method ensures developers must create a notification with startForeground(notificationId, notification) within five seconds of calling ContextCompat.startForegroundService(...) in order to ensure the user is aware of the foreground service running even when the app is not in view.

For any devices running Nougat API level 25 or lower make sure to unbind the service manually.

ie

override fun onDestroy() {
    if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.N_MR1) 
        context?.unbindService(serviceConnection)
}

Leave a Reply

Your email address will not be published. Required fields are marked *