Activity <App Name> has leaked ServiceConnection <ServiceConnection Name>@438030a8 that was originally bound here
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;
}
catdotgif
Updated on August 20, 2022Comments
-
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 afterstartService()
, 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()
andonDestroy()
:/** 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 theironResume()
andonDestroy()
:@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 theonDestroy()
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 anonUnBind()
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 over 11 yearsI 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 over 11 yearsas you might have eyperienced onDestroy is pretty much never called from the operating system
-
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 over 7 yearsWhat is the solution for continue service in a background for music player ?
-
Blaze Gawlik about 6 yearsSee 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 about 4 yearsExcellent. Thats what it is.