Android:绑定服务被销毁时如何避免服务连接泄漏
Android: How to avoid service connection leak when bound service is destroyed
我想就此问题寻求帮助。这看起来很常见,但我没有在任何地方找到答案。只提到here
我有一个服务 A 使用服务连接 C 绑定到第二个服务 B。
- A 正在运行并绑定到 B
- B 停止并销毁(无错误状态 - 它正常完成)
- onServiceDisconnected() 在 C 上调用
- 我发现一些关于这个的提及,它不是正常调用的。但是当B被销毁时我可以观察到它。
- 现在用C应该怎么办?
- 根据guide,我应该什么都不做(因为B被破坏并断开连接)。但是这样会导致A被销毁时出现service leak异常,因为C还处于活动状态!
所以我的问题是:错误在哪里?在我的场景或谷歌的指南中。
我尝试将 A 中的代码更改为以下形式,看起来效果很好,但很丑陋:
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
boolean bound = false;
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((MyService.ServiceBinder) service).getService();
if (!bound)
{
// do some action - service is bound for the first time
bound = true;
}
}
};
@Override
public void onDestroy()
{
if (mService != null)
{
// do some finalization with mService
}
if (mServiceConnection.bound)
{
mServiceConnection.bound = false;
unbindService(mServiceConnection);
}
super.onDestroy();
}
public void someMethod()
{
if (mService != null)
{
// I have to test mService, not mServiceConnection.bound
}
}
还有其他正确处理方法吗?非常感谢您的帮助或意见。
您考虑过使用管道吗?
这样就可以实现良好的通信,无需两个服务。
如果你想了解更多关于高效多线程的信息,我推荐阅读这本书:
Efficient multi threading in Android
转到第 4 章第 39 页,这里有完整的管道和相关内容的章节。
所以我使用了问题中的方法并将其包装到 SafeServiceConnection class。我知道通常在所有绑定未绑定之前服务不会被破坏,但这并不总是需要的行为。
public class SafeServiceConnection<T extends Service> implements ServiceConnection
{
private final Logger log = new Logger(SafeServiceConnection.class);
boolean mBound = false;
T mService;
@SuppressWarnings("unchecked")
@Override
final public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((ServiceBinder<T>) service).getService();
if (mService == null)
{
return;
}
if (!mBound)
{
mBound = true;
onServiceConnected(name, mService, true);
}
else
{
onServiceConnected(name, mService, false);
}
}
public void onServiceConnected(ComponentName name, T service, boolean firstConnection)
{
}
@Override
final public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
public void bind(Context context, Intent intent, int flags)
{
context.bindService(intent, this, flags);
}
public void bind(Context context, Intent intent)
{
bind(context, intent, Context.BIND_AUTO_CREATE);
}
public void startAndBind(Context context, Intent intent)
{
context.startService(intent);
bind(context, intent);
}
public void unbind(Context context)
{
if (mBound)
{
if (context != null)
{
context.unbindService(this);
}
else
{
log.e("Context is null");
}
mBound = false;
}
}
public T getService()
{
return mService;
}
public boolean isConnected()
{
return mService != null;
}
}
我想就此问题寻求帮助。这看起来很常见,但我没有在任何地方找到答案。只提到here
我有一个服务 A 使用服务连接 C 绑定到第二个服务 B。
- A 正在运行并绑定到 B
- B 停止并销毁(无错误状态 - 它正常完成)
- onServiceDisconnected() 在 C 上调用
- 我发现一些关于这个的提及,它不是正常调用的。但是当B被销毁时我可以观察到它。
- 现在用C应该怎么办?
- 根据guide,我应该什么都不做(因为B被破坏并断开连接)。但是这样会导致A被销毁时出现service leak异常,因为C还处于活动状态!
所以我的问题是:错误在哪里?在我的场景或谷歌的指南中。
我尝试将 A 中的代码更改为以下形式,看起来效果很好,但很丑陋:
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
boolean bound = false;
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((MyService.ServiceBinder) service).getService();
if (!bound)
{
// do some action - service is bound for the first time
bound = true;
}
}
};
@Override
public void onDestroy()
{
if (mService != null)
{
// do some finalization with mService
}
if (mServiceConnection.bound)
{
mServiceConnection.bound = false;
unbindService(mServiceConnection);
}
super.onDestroy();
}
public void someMethod()
{
if (mService != null)
{
// I have to test mService, not mServiceConnection.bound
}
}
还有其他正确处理方法吗?非常感谢您的帮助或意见。
您考虑过使用管道吗?
这样就可以实现良好的通信,无需两个服务。
如果你想了解更多关于高效多线程的信息,我推荐阅读这本书:
Efficient multi threading in Android
转到第 4 章第 39 页,这里有完整的管道和相关内容的章节。
所以我使用了问题中的方法并将其包装到 SafeServiceConnection class。我知道通常在所有绑定未绑定之前服务不会被破坏,但这并不总是需要的行为。
public class SafeServiceConnection<T extends Service> implements ServiceConnection
{
private final Logger log = new Logger(SafeServiceConnection.class);
boolean mBound = false;
T mService;
@SuppressWarnings("unchecked")
@Override
final public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((ServiceBinder<T>) service).getService();
if (mService == null)
{
return;
}
if (!mBound)
{
mBound = true;
onServiceConnected(name, mService, true);
}
else
{
onServiceConnected(name, mService, false);
}
}
public void onServiceConnected(ComponentName name, T service, boolean firstConnection)
{
}
@Override
final public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
public void bind(Context context, Intent intent, int flags)
{
context.bindService(intent, this, flags);
}
public void bind(Context context, Intent intent)
{
bind(context, intent, Context.BIND_AUTO_CREATE);
}
public void startAndBind(Context context, Intent intent)
{
context.startService(intent);
bind(context, intent);
}
public void unbind(Context context)
{
if (mBound)
{
if (context != null)
{
context.unbindService(this);
}
else
{
log.e("Context is null");
}
mBound = false;
}
}
public T getService()
{
return mService;
}
public boolean isConnected()
{
return mService != null;
}
}