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


134

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

编辑 谢谢BDLS为您提供丰富的答案。根据您对bindService()用作独立功能或after之后的区别的澄清,我已经重新编写了代码,startService()现在当使用后退按钮在活动之间循环时,我只会间歇性地收到泄漏错误消息。

我的连接活动具有以下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()函数中,如果需要的话,它是未绑定的。

结束编辑

但是在切换活动时,我仍然间歇性地收到内存泄漏错误消息“活动泄漏了最初绑定在这里的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

编辑第二
次再次感谢bdls提供您的建议。我按照您的建议做了,onUnBind()并向该服​​务添加了覆盖。 onUnBind()实际上只有在所有客户端都从服务断开连接时才会触发,但是当我按下home按钮时,它就会执行,然后弹出错误消息!这对我来说毫无意义,因为所有客户端都已解除服务绑定,那么被销毁的客户端又怎么可能泄漏serviceConnection?看看这个:

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()调用时与服务的绑定未完成,但是当我支持每个活动来验证绑定是否完成时,我尝试在服务上调用方法通过罚款。

通常,此行为似乎与我在每个活动中停留的时间无关。但是,一旦第一个活动泄漏了它的serviceConnection,它们都会像我一样通过它们返回。

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

有任何想法吗?


您可以添加LightfactoryRemote.onCreate()代码吗?(com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate(LightfactoryRemote.java:97))
tbruyelle

Answers:


57

您没有提供来自的任何代码LightFactoryRemote,因此这只是一个假设,但是如果您bindService自己使用该方法,则看起来就像是种问题。

为了确保服务保持运行,即使在启动该服务的活动onDestroy调用了其方法之后,也应首先使用startService

用于startService状态的android文档:

使用startService()会覆盖由bindService(Intent,ServiceConnection,int)管理的默认服务生存期:它要求服务保持运行直到调用stopService(Intent)为止,无论是否连接了任何客户端。

bindService

只要调用上下文存在,系统就认为该服务是必需的。例如,如果此上下文是已停止的活动,则在恢复该活动之前,不需要该服务继续运行。


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


在此示例中,无论呼叫活动是否正在运行,服务都应保持运行状态。

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

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


我使用START_STICKY启动该服务,它也通过启动意图启动。如果我调用StartService,它将创建该服务的另一个实例,并且我不希望同时运行2个服务。在这种情况下,如何解决错误?
opc0de 2012年

16
@ opc0de,不,您两次调用startService()时不会创建另一个服务。本质上,服务在逻辑上是单例的。无论您启动它多少次,都只会运行一项服务。
mahkie

2
在音乐播放器中继续提供服务的解决方案是什么?
阿南德·萨瓦尼


31

您绑定onResume但未绑定onDestroy。您应该onPause改为进行取消绑定,以便始终有匹配的绑定/取消绑定调用对。您的间歇性错误将是您的活动被暂停但未被破坏,然后再次恢复的地方。


13

您只需要取消绑定中的服务onDestroy()。然后,警告将消失。

这里

正如“活动”文档试图解释的那样,您将使用三个主要的绑定/取消绑定分组:onCreate()和onDestroy(),onStart()和onStop()以及onResume()和onPause()。


7
如您所知,onDestroy几乎从未从操作系统中调用过
martyglaubitz 2012年

请参阅此处链接到禁止内容->禁止内容警告。任何人都可以访问吗?“继续分组”按钮仅刷新页面并为我显示相同的警告。
Blaze Gawlik

11

您提到用户很快在“活动”之间切换。unbindService服务连接建立之前是否正在打电话?这可能会导致无法解除绑定,然后泄漏绑定的后果。

不完全确定如何处理此问题...也许在onServiceConnected被调用时可以调用(unbindService如果onDestroy已调用)。不确定是否可以。


如果还没有的话,可以在服务中添加onUnbind方法。这样,您可以确切地看到您的类何时从中解除绑定,这可能有助于调试。

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

2

尝试在OnUserLeaveHint()中使用unbindService()。它可以防止ServiceConnection泄漏情况和其他异常。
我在代码中使用了它,效果很好。


1

您可以使用布尔值控制它,因此只有在进行绑定后才调用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;
    }
};

0

活动中绑定的每个服务都必须在应用关闭时解除绑定。

所以尝试使用

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

0

我最近一直在阅读有关Android Service的文章,并有机会深入了解它。我遇到了服务泄漏,就我的情况而言,这是因为我有一个未绑定的服务正在启动一个绑定的服务,但是在这种情况下,我的未绑定服务被Activity取代了。

因此,当我使用stopSelf()停止我的未绑定服务时,发生了泄漏,原因是我在不取消绑定服务的情况下停止了父服务。现在绑定的服务正在运行,并且它不知道它属于谁。

简单而直接的解决方法是您应该调用unbindService(YOUR_SERVICE); 在 父“活动/服务”的onDestroy()函数中。这样,生命周期将确保在父活动/服务出现故障之前停止或清理绑定的服务。

此问题还有另一种变化。有时,在绑定服务中,您希望某些功能仅在绑定服务时才起作用,因此我们最终将绑定标志放在onServiceConnected中,如下所示:

public void onServiceConnected(ComponentName name, IBinder service) {
            bounded = true;
            // code here
        }

到这里为止都可以正常工作,但是当我们将onServiceDisconnected函数作为unbindService函数调用的回调时,问题就来了,只有在服务被终止或崩溃时才通过文档调用此方法。而且您永远不会同一线程中获得此回调。因此,我们最终会做类似的事情:

public void onServiceDisconnected(ComponentName name) {
            bounded = false;
        }

这会在代码中造成重大错误,因为我们的绑定标志永远不会重置为false,并且在大多数情况下重新连接此服务时,就不会这样做true。因此,为避免发生这种情况,应bound在呼叫时将设置为false unbindService

这是Erik 博客中的详细介绍。

希望曾经来过这里的人感到好奇。


0

当您绑定绑定服务时,会发生此错误。因此,sol应该是:-

  1. 在服务连接中添加serviceBound,如下所示:

    private final ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // your work here.
    
        serviceBound = true;
    
    }
    
    @Override
    public void onServiceDisconnected(ComponentName name) {
    
        serviceBound = false;
    }

    };

  2. 取消绑定服务onDestroy

        if (serviceBound) {
            unbindService(serviceConnection);
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.