Activity < App Name > 泄露了原本绑定在这里的 ServiceConnection < ServiceConnection Name >@438030a8

我正在开发我的第一个 Android 应用程序。我的应用程序中有三个活动,用户来回切换非常频繁。我还有一个远程服务,可以处理 telnet 连接。应用程序需要绑定到这个服务,以便发送/接收 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 已经泄漏了 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

编辑第二部
再次感谢你的建议。我按照你的建议给服务添加了 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,它们就会像我在之后返回它们一样进行操作。

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

有什么想法吗?

140608 次浏览

您还没有提供来自 LightFactoryRemote的任何代码,所以这只是一个假设,但是如果您单独使用 bindService方法,那么看起来就会出现这种问题。

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

StartService的机器人文档是:

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

BindService:

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


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


例子

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

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

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

您提到了用户在活动之间快速切换。是不是在服务连接建立之前您就在调用 unbindService?这可能会导致解除绑定失败,然后泄漏绑定。

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


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

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

onResume中绑定,但在 onDestroy中解除绑定。您应该在 onPause中解除绑定,以便始终存在匹配的 bind/unbind 调用对。您的间歇性错误将是您的活动被暂停但没有被销毁,然后再次恢复的地方。

尝试在 OnUserLeaveHint ()中使用 unbindService ()。
我在代码中使用它,工作得很好。

您只需要在 onDestroy()中解除对服务的绑定。然后,警告就会消失。

参见 给你

正如 Activity 文档试图解释的那样,有三个主要的 bind/unbind 您将使用的分组: onCreate ()和 onDestroy ()、 onStart ()和 OnStop () ,onResume ()和 onPuse ()。

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

那就试试用

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

你可使用:

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


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

您可以只使用一个布尔值来控制它,因此只有在已经执行 bind 时才调用 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;
}
};

我最近一直在阅读关于 Android 服务的文章,并且有机会深入研究它。我遇到了一个服务泄漏,对于我的情况它发生了,因为我有一个 不受约束服务正在启动一个 约束服务,但是在这里我的 不受约束服务被一个 活动所取代。

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

简单而直接的解决办法是你应该在你的 OnDestroy ()函数中调用 解除绑定服务(YOUR _ SERVICE) ;在你的父母的活动/服务。通过这种方式,生命周期将确保在您的父活动/服务停止之前停止或清理绑定的服务。

这个问题还有另外一种变体。有时,在绑定服务中,您希望某些函数仅在服务被绑定时才能工作,因此我们最终在 OnServiceConnected中放置一个绑定标志,比如:

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

在此之前,这种方法工作得很好,但是当我们将 OnService 断开连接函数视为 解除绑定服务函数调用的回调时,问题就出现了,根据文档,只有当服务为 死亡或坠毁时才会调用这种方法。你将在 同样的线索中得到这个回调。因此,我们最终会这样做:

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

这在代码中造成了很大的错误,因为我们的 绑旗从来没有被重置为 false,当这个服务再次连接回来时,大多数时候它是 true。因此,为了避免这种情况,您应该在调用 unbindService的同时将 bound设置为 false。

这是埃里克的 博客中更详细的描述。

希望曾经来过这里的人满足了他的好奇心。

当您要绑定一个有界服务时,就会发生这个错误。因此,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. 销毁解除绑定服务

        if (serviceBound) {
    unbindService(serviceConnection);
    }