【问题标题】:Activity <App Name> has leaked ServiceConnection <ServiceConnection Name>@438030a8 that was originally bound hereActivity <App Name> 泄露了原来绑定在这里的ServiceConnection <ServiceConnection Name>@438030a8
【发布时间】:2010-12-31 20:24:15
【问题描述】:

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

编辑 感谢 BDLS 提供的信息丰富的回答。根据您对使用bindService() 作为独立函数或在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() 函数中取消绑定(如有必要)。

结束编辑

但我在切换活动时仍然间歇性地收到内存泄漏错误消息“Activity has leaked ServiceConnection @438030a8 that original bound here”。我做错了什么?

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

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

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() 实际上只有在所有客户端断开服务时才会触发,但是当我点击主页按钮时,它执行了,然后弹出错误消息!这对我来说毫无意义,因为所有客户端都已与服务解除绑定,那么被破坏的客户端怎么会泄漏 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))

标签: android serviceconnection


【解决方案1】:

您没有提供来自LightFactoryRemote 的任何代码,因此这只是一个假设,但如果您单独使用bindService 方法,您可能会遇到这种问题。

为确保服务保持运行,即使在启动它的 Activity 已调用其 onDestroy 方法后,您也应首先使用 startService

startService 状态的 android 文档:

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

而对于bindService

只要调用上下文存在,系统就会认为该服务是必需的。例如,如果这个 Context 是一个停止的 Activity,那么在 Activity 恢复之前,服务将不需要继续运行。


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


示例

在此示例中,无论调用活动是否正在运行,服务都应保持运行。

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

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

【讨论】:

  • 我使用 START_STICKY 启动服务,它也是由引导意图启动的。如果我调用 StartService 它会创建该服务的另一个实例,并且我不希望同时运行 2 个服务。在这种情况下如何解决错误?
  • @opc0de,不,当您调用 startService() 两次时,您并没有创建另一个服务。服务本质上是逻辑上的单例。不管你启动多少次,只运行一个服务。
  • 音乐播放器后台继续服务的解决方案是什么?
【解决方案2】:

您提到用户在活动之间切换的速度非常快。可能是您在建立服务连接之前调用unbindService 吗?这可能会导致无法取消绑定,然后泄漏绑定。

不完全确定如何处理这个问题...也许当onServiceConnected 被调用时,如果onDestroy 已经被调用,你可以调用unbindService。不过不确定这是否可行。


如果您还没有,您可以向您的服务添加一个 onUnbind 方法。这样你就可以准确地看到你的类何时解除绑定,这可能有助于调试。

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        here

        正如 Activity 文档试图解释的那样,主要有 3 个绑定/取消绑定 您将使用的分组:onCreate() 和 onDestroy()、onStart() 和 onStop()、onResume() 和 onPause()。

        【讨论】:

        • 您可能已经体验过 onDestroy 几乎从未从操作系统调用
        • 查看此处链接转发到禁止内容 --> 禁止内容警告。任何人都可以访问吗? “继续分组”按钮只是刷新页面并向我显示相同的警告。
        【解决方案6】:

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

        所以尝试使用

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

        【讨论】:

          【解决方案7】:

          你可以使用:

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

          【讨论】:

          • 优秀。就是这样。
          【解决方案8】:

          你可以用一个布尔值来控制它,所以你只有在绑定时才调用 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;
              }
          };
          

          【讨论】:

            【解决方案9】:

            我最近一直在阅读有关 Android 服务的信息,并有机会深入研究它。我遇到了服务泄漏,因为我有一个 unbound 服务正在启动一个 bound 服务,但在这个我的 unbound 服务被 Activity 取代。

            所以当我使用 stopSelf() 停止我的未绑定服务时,发生了泄漏,原因是我停止了父 service 没有解除绑定服务。现在绑定的服务正在运行,它不知道它属于谁。

            简单直接的解决方法是您应该在父 Activity/Service 的 onDestroy() 函数中调用 unbindService(YOUR_SERVICE);。这样,生命周期将确保您的绑定服务在您的父 Activity/Services 关闭之前停止或清理。

            这个问题还有另一种变体。有时在您的绑定服务中,您希望某些功能仅在服务已绑定时才能工作,因此我们最终在onServiceConnected 中放置了一个绑定标志,例如:

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

            到这里为止都可以正常工作,但是当我们将 onServiceDisconnected 函数视为 unbindService 函数调用的回调时,问题就来了,文档中的 this 仅在服务被 杀死或崩溃时调用。而且您将永远不会同一线程中获得此回调。因此,我们最终会执行以下操作:

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

            这会在代码中造成重大错误,因为我们的 bound 标志 永远不会重置为 false,并且当此服务再次连接回来时,大多数时候它是 true。因此,为了避免这种情况,您应该在调用 unbindService 时将 bound 设置为 false。

            这在 Erik 的blog 中有更详细的介绍。

            希望来过这里的人能满足他的好奇心。

            【讨论】:

              【解决方案10】:

              当您要绑定有界服务时会发生此错误。所以,溶胶应该是:-

              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);
                    }
                

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-11-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-11-14
                相关资源
                最近更新 更多