ServiceConnectionLeaked in Android

MrMannWood picture MrMannWood · Sep 2, 2013 · Viewed 24k times · Source

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.

Answer

BinqiangSun picture BinqiangSun · Dec 20, 2014

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

It works for me.