活动<应用程序名称>泄露了最初在此处绑定的ServiceConnection <ServiceConnection名称> @ 438030a8

我正在开发我的第一个Android应用程序。 我在我的应用程序中有三个活动,用户频繁地来回切换。 我也有一个远程服务,它处理一个telnet连接。 应用程序需要绑定到此服务才能发送/接收telnet消息。

编辑谢谢BDLS您的丰富答案。 根据您对使用bindService()作为独立函数或在startService()之后的区别的说明,我已经重新编写了我的代码,现在我只使用后退button来间歇性地获取泄漏错误消息活动。

我的连接活动有以下onCreate()和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() 

因此,服务在活动启动时启动,如果没有成功的telnet连接(connectStatus == 0),活动就会被终止。 其他活动只有在连接成功的情况下才会绑定到服务(connectStatus == 1,保存到共享首选项)。 这里是他们的onResume()和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() 

因此,绑定发生在onResume(),以便它将从连接活动中获取已更改的状态,如果需要,在onDestroy()函数中它将被解除绑定。

结束编辑

但是当切换活动时,我仍然得到了内存泄漏错误信息“Activity has leakage ServiceConnection @ 438030a8,原来是在这里绑定的”。 我究竟做错了什么?

提前感谢任何提示或指针!

完整的错误信息如下(来自修改后的代码):

 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 

编辑第二个
再次感谢您的build议。 我按照你的build议做了,并添加一个onUnBind()覆盖到服务。 onUnBind()实际上只有当所有的客户端从服务断开时才被触发,但是当我点击主页button时,它会执行,然后popup错误消息! 这对我来说没有任何意义,因为所有的客户都已经从服务中解脱出来,那么如何销毁服务连接呢? 一探究竟:

 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 

我认为这可能是像你说的,当绑定到服务是不完整的时候调用unbindService(),但我试着调用服务的方法,因为我支持通过每个活动来validation绑定是完整的,他们都过得很好。

一般来说,这种行为似乎并不涉及我在每个活动中停留多久。 一旦第一个活动泄露了它的服务连接,然而,他们都做了我之后通过他们。

另一件事,如果我打开“开发工具”中的“立即销毁活动”,它可以防止这个错误。

有任何想法吗?

你还没有从LightFactoryRemote提供任何你的代码,所以这只是一个假设,但是如果你自己使用了bindService方法的话你会看到这样的问题。

为确保服务继续运行,即使在启动它的活动已经调用了onDestroy方法之后,也应该先使用startService

startService状态的android文档:

使用startService()覆盖由bindService(Intent,ServiceConnection,int)pipe理的默认服务生命周期:它要求服务保持运行直到stopService(Intent)被调用,而不pipe客户端是否连接到它。

而对于bindService :

只要存在调用上下文,该服务将被认为是系统要求的。 例如,如果此上下文是一个已停止的活动,则该服务将不需要继续运行,直到活动恢复。


那么发生什么事是绑定(并因此启动)服务的活动已经停止,因此系统认为服务不再需要并导致该错误(并且可能停止该服务)。


在这个例子中,服务应该保持运行,不pipe调用活动是否在运行。

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

第一行开始服务,第二行将其绑定到活动。

你在onResume绑定,但在onDestroy解除绑定。 您应该在onPause进行解除绑定,以便始终存在匹配的绑定/解除绑定对的对。 您的间歇性错误将是您的活动暂停但未销毁的位置,然后再次恢复。

您可以使用:

 @Override public void onDestroy() { super.onDestroy(); if (mServiceConn != null) { unbindService(mServiceConn); } } 

您应该只需要解除onDestroy()的服务绑定。 然后,警告将会消失。

看到这里 。

如Activity文档试图解释的那样,有三个主要的绑定/解除绑定分组:onCreate()和onDestroy(),onStart()和onStop()以及onResume()和onPause()。

你提到用户之间切换活动很快。 在服务连接build立之前,是否可以调用unbindService ? 这可能会导致无法解绑,然后泄漏绑定。

不完全确定你可以如何处理这个…也许当onServiceConnected被调用,你可以调用unbindService如果onDestroy已经被调用。 不知道这是否会工作。


如果你还没有,你可以添加一个onUnbind方法到你的服务。 这样你就可以清楚地看到你的类什么时候解除绑定了,这可能有助于debugging。

 @Override public boolean onUnbind(Intent intent) { Log.d(this.getClass().getName(), "UNBIND"); return true; } 

尝试在OnUserLeaveHint()中使用unbindService()。 它可以防止ServiceConnection泄漏的场景和其他exception。
我用它在我的代码,并正常工作。

每个绑定在活动中的服务必须在应用程序closures时解除绑定。

所以请尝试使用

  onPause(){ unbindService(YOUR_SERVICE); super.onPause(); } 

你可以用布尔值来控制它,所以如果绑定已经被创build,你只能调用unbind

 public void doBindService() { if (!mIsBound) { bindService(new Intent(this, DMusic.class), Scon, Context.BIND_AUTO_CREATE); mIsBound = true; } } public void doUnbindService() { if (mIsBound) { unbindService(Scon); mIsBound = false; } } 

如果你只想解除绑定它,如果它已经连接

 public ServiceConnection Scon = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder binder) { mServ = ((DMusic.ServiceBinder) binder).getService(); mIsBound = true; } public void onServiceDisconnected(ComponentName name) { mServ = null; } }; 
Interesting Posts