Activity <App Name> has leaked ServiceConnection <ServiceConnection Name>@438030a8 that was originally bound here

137,806

Solution 1

You haven't provided any of your code from LightFactoryRemote, so this is only a presumption, but it looks like the kind of problem you'd be seeing if you were using the bindService method on it's own.

To ensure a service is kept running, even after the activity that started it has had its onDestroy method called, you should first use startService.

The android docs for startService state:

Using startService() overrides the default service lifetime that is managed by bindService(Intent, ServiceConnection, int): it requires the service to remain running until stopService(Intent) is called, regardless of whether any clients are connected to it.

Whereas for bindService:

The service will be considered required by the system only for as long as the calling context exists. For example, if this Context is an Activity that is stopped, the service will not be required to continue running until the Activity is resumed.


So what's happened is the activity that bound (and therefore started) the service, has been stopped and thus the system thinks the service is no longer required and causes that error (and then probably stops the service).


Example

In this example the service should be kept running regardless of whether the calling activity is running.

ComponentName myService = startService(new Intent(this, myClass.class));
bindService(new Intent(this, myClass.class), myServiceConn, BIND_AUTO_CREATE);

The first line starts the service, and the second binds it to the activity.

Solution 2

You can use:

@Override
public void onDestroy() {
    super.onDestroy();

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}

Solution 3

You bind in onResume but unbind in onDestroy. You should do the unbinding in onPause instead, so that there are always matching pairs of bind/unbind calls. Your intermittent errors will be where your activity is paused but not destroyed, and then resumed again.

Solution 4

You should only need to unbind the service in onDestroy(). Then, The warning will go.

See here.

As the Activity doc tries to explain, there are three main bind/unbind groupings you will use: onCreate() and onDestroy(), onStart() and onStop(), and onResume() and onPause().

Solution 5

You mention the user switching between Activities pretty quickly. Could it be that you're calling unbindService before the service connection has been established? This may have the effect of failing to unbind, then leaking the binding.

Not entirely sure how you could handle this... Perhaps when onServiceConnected is called you could call unbindService if onDestroy has already been called. Not sure if that'll work though.


If you haven't already, you could add an onUnbind method to your service. That way you can see exactly when your classes unbind from it, and it might help with debugging.

@Override
public boolean onUnbind(Intent intent) {
    Log.d(this.getClass().getName(), "UNBIND");
    return true;
}
Share:
137,806
catdotgif
Author by

catdotgif

Updated on August 20, 2022

Comments

  • catdotgif
    catdotgif almost 2 years

    I'm working on my first Android app. I've got three activities in my app, and the user switches back and forth pretty frequently. I've also got a remote service, which handles a telnet connection. The apps need to bind to this service in order to send/receive telnet messages.

    Edit Thank you BDLS for your informative answer. I have re-written my code in light of your clarification on the difference between using bindService() as a stand-alone function or after startService(), and I now only get the leak error message intermittently when using the back button to cycle between activities.

    My connection activity has the following onCreate() and onDestroy():

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        /*
         * Initialize the ServiceConnection.  Note that this is the only place startService() is run.
         * It is also the only time bindService is run without dependency on connectStatus.
         */
        conn = new TelnetServiceConnection();
        //start the service which handles telnet
        Intent i = new Intent();
        i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
        startService(i);
        //bind to the service
        bindService(i, conn, 0);
    
        setContentView(R.layout.connect);
        setupConnectUI();
    
    }//end OnCreate()
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
    
        //unbind the service and null it out
        if (conn != null) {
            unbindService(conn);
            conn = null;
            }
    
        if(connectStatus == 0) {
            //stop the service
            Intent i = new Intent();
            i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
            stopService(i);
            Log.d("LightfactoryRemote", "Connect onDestroy() attempted to stop service");
            }
    
        Log.d("LightfactoryRemote", "Connect onDestroy()");
        }//end onDestroy()
    

    So the service is started when the activity is started, and stopped when the activity is destroyed if no successful telnet connection was made (connectStatus == 0). The other activities bind to the service only if a successful connection was made (connectStatus == 1, saved to a shared preferences). Here is their onResume() and onDestroy():

    @Override
    protected void onResume() {
        super.onResume();
    
        //retrieve the shared preferences file, and grab the connectionStatus out of it.
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_WORLD_WRITEABLE);
        connectStatus = settings.getInt("connectStatus", 0);
    
        Log.d("LightfactoryRemote", "Focus onResume with " + connectStatus);
    
        //if a telnet connection is active, start the service and bind to it
        if (connectStatus == 1) {
            conn = new TelnetServiceConnection();
            Intent i = new Intent();
            i.setClassName("com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService");
            bindService(i, conn, 0);
            //TODO write restore texview code
            }//end if
        }//end onResume
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //unbind the service and null it out.
        if (conn != null) {
            Log.d("LightfactoryRemote", "Focus onDestroy() attempted to unbind service");
            unbindService(conn);
            conn = null;
            }
        Log.d("LightfactoryRemote", "Focus onDestroy()");
        }//end onDestroy()
    

    So the binding happens in onResume() so that it will pick up the changed state from the connection activity, and in the onDestroy() function it is unbound, if necessary.

    End Edit

    But I still get the memory leak error message "Activity has leaked ServiceConnection @438030a8 that was originally bound here" intermittently when switching activities. What am I doing wrong?

    Thanks in advance for any tips or pointers!!!

    Full error message follows (from the revised code):

    01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onStop()
    01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy() attempted to unbind service
    01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy()
    01-02 22:04:26.672: ERROR/ActivityThread(2024): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
    01-02 22:04:26.672: ERROR/ActivityThread(2024): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:927)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:822)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ApplicationContext.bindService(ApplicationContext.java:842)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.content.ContextWrapper.bindService(ContextWrapper.java:319)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Activity.performResume(Activity.java:3559)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2838)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2866)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.access$2100(ActivityThread.java:116)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Handler.dispatchMessage(Handler.java:99)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Looper.loop(Looper.java:123)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.main(ActivityThread.java:4203)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invokeNative(Native Method)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invoke(Method.java:521)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
    01-02 22:04:26.672: ERROR/ActivityThread(2024):     at dalvik.system.NativeStart.main(Native Method)
    01-02 22:04:26.692: WARN/ActivityManager(558): Unbind failed: could not find connection for android.os.BinderProxy@43c509a8
    

    Edit the 2nd
    Thanks once again bdls for your suggestions. I did as you suggested and added an onUnBind() override to the service. onUnBind() is actually only triggered when all clients disconnect from the service, but when I hit the home button, it executed, then the error message popped up! This makes no sense to me, as all the clients have been unbound from the service, so how could the one destroyed leak a serviceConnection? Check it out:

    01-03 19:38:30.837: DEBUG/LightfactoryRemote(1118): Focus onPause()1
    01-03 19:38:31.577: WARN/IInputConnectionWrapper(1118): showStatusIcon on inactive InputConnection
    01-03 19:38:31.587: DEBUG/LightfactoryRemote(1118): Focus onStop()
    01-03 19:38:31.600: DEBUG/LightfactoryRemote(1118): Focus onDestroy() attempted to unbind service
    01-03 19:38:31.607: DEBUG/LightfactoryRemote(1118): Focus onDestroy()
    01-03 19:38:31.677: DEBUG/LightfactoryRemote(1125): TelnetService onUnBind()
    01-03 19:38:31.727: ERROR/ActivityThread(1118): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
    01-03 19:38:31.727: ERROR/ActivityThread(1118): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Activity.performResume(Activity.java:3530)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2647)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2287)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Handler.dispatchMessage(Handler.java:99)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Looper.loop(Looper.java:123)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.main(ActivityThread.java:3948)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invokeNative(Native Method)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invoke(Method.java:521)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
    01-03 19:38:31.727: ERROR/ActivityThread(1118):     at dalvik.system.NativeStart.main(Native Method)
    01-03 19:38:31.777: WARN/ActivityManager(564): Unbind failed: could not find connection for android.os.BinderProxy@4370f8a8
    

    I thought it might be something like you said, where the binding to the service is not complete when unbindService() is called, however I tried calling a method on the service as I backed through each activity to verify that the binding is complete, and they all went through fine.

    In general, this behavior doesn't seem related to how long I stay in each activity. Once the first activity leaks its serviceConnection, however, they all do as I back through them after that.

    One other thing, if I turn on "Immediately destroy activities" in Dev Tools, it prevents this error.

    Any ideas?

  • opc0de
    opc0de over 11 years
    I start the service using START_STICKY and it's started also by the boot intent. If I call StartService it creates another instance of the service and I don't want 2 services running at the same time. How can I fix the error in this case ?
  • martyglaubitz
    martyglaubitz over 11 years
    as you might have eyperienced onDestroy is pretty much never called from the operating system
  • mahkie
    mahkie over 11 years
    @opc0de, no you are not creating another service when you call startService() twice. Services are logically singletons by nature. No matter how many times you start it, only one service runs.
  • Anand Savjani
    Anand Savjani over 7 years
    What is the solution for continue service in a background for music player ?
  • Blaze Gawlik
    Blaze Gawlik about 6 years
    See here link forwards to banned content --> Banned Content Warning. Can anyone get access? The "Continue to Group" button just refreshes the page and shows the same warning for me.
  • Seltsam
    Seltsam about 4 years
    Excellent. Thats what it is.