我有一个在单独进程中运行的服务。我发现在主进程UI线程从onDestroy()退出之后我的服务正在被销毁,即使我已经为应用程序上下文提供了绑定并指定了BIND_AUTO_CREATE。
在我的主进程'UI thread onCreate()中,我有这个绑定代码:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
在我的主进程'UI thread onDestroy()中,我有这个无法解释的代码:
mAppContext.unbindService(mMyServiceConnection);
请注意,我从不调用stopService()。
Android的bindService()文档说:
只要存在调用上下文,系统就会认为该服务是必需的。
如果我正确阅读,因为我提供了应用程序的上下文,系统认为该服务在应用程序的生命周期内是必需的。
我原以为应用程序的上下文可能会与onDestroy()一起消失。这就是Android的文档对getApplicationContext()所说的:
返回当前进程的单个全局Application对象的上下文。
如果应用程序的上下文死于onDestroy(),那么我认为Android有一个大问题。问题是当旋转显示时,调用onDestroy()(紧接着是onCreate())。因此效果是当显示器旋转时 - 在我的情况下它经常发生! - 我的服务总是退出。
请注意,我的应用程序进程的pid永远不会更改,即它是相同的进程。根据getApplicationContext()的文档说明“当前进程”,这很重要。
以下是我的调试日志显示的内容:
04-03 05:15:12.874:DEBUG / MyApp(841):主要onDestroy
04-03 05:15:12.895:DEBUG / MyApp(847):服务onUnbind
04-03 05:15:12.895:DEBUG / MyApp(847):service onDestroy
04-03 05:15:12.934:DEBUG / MyApp(841):main onCreate
04-03 05:15:12.966:DEBUG / MyApp(847):service onCreate
04-03 05:15:12.975:DEBUG / MyApp(847):service onBind
所以我的问题是:
1)我对绑定/解除绑定的理解是否正确?
2)当调用UI线程的onDestroy()时,有没有办法让我的服务不被破坏?
问题#2的黑客攻击永远不会解开。但是我不喜欢它,因为每次调用onDestroy()时我都会泄漏一个绑定。我可以“记住”我有一个泄漏的绑定,只泄漏那个,但后来我有级联黑客,它真的很难看。
答案 0 :(得分:4)
1)是的,我认为你的理解是正确的(我说我想是因为我认为我理解你在说什么;-))。您正在使用的标志意味着“如果有人试图绑定它并且只要有人绑定它就会自动启动它,但是一旦没有人绑定它,就可以自由地杀死它”。
2)按照here所述查看START_STICKY
标志。这应该允许您启动服务并使其保持运行,无论调用Context
一般情况下,onDestroy()
表示您的活动即将被杀死。旋转显示时,Activity
将被终止并重新创建。您有责任在适当的方法中将任何州保存到Bundle
,然后在onCreate()
中恢复。
答案 1 :(得分:0)
您的服务是否被杀死:
Activity
?为什么您的应用程序被销毁后需要您的服务才能保持活力?
我认为一般的经验法则是您无法确定何时会杀死您的活动和服务。如果这阻碍了你想要实现的目标,可能会有一个聪明的方法。
编辑 - 您实际上可以处理方向配置更改,以便不重新启动您的活动。有关详细信息,请参阅this answer的后半部分。
关于“第二个”Activity
:您开始活动的图片A
,然后是活动B
。现在,您在显示B
时旋转屏幕,导致B
重新启动。此时会重新启动A
吗?我不确定,但我预感A
将会保持活着并在方向改变期间保持你的应用程序活着。如果这是你的目标,那么这可能是让你的服务保持活力的另一种策略。
答案 2 :(得分:0)
只有满足以下两个条件时,服务才会被销毁:
服务既可以启动,也可以绑定连接。在这种情况下,只要系统启动或者使用Context.BIND_AUTO_CREATE标志有一个或多个连接,系统就会保持服务运行。一旦这些情况都不成立,就会调用服务的onDestroy()方法,并且服务会被有效终止。
这提供了一个非常正确和安全的好解决方案!
假设有两个活动(在本例中为'viewer'和'chat')需要服务,如果是bindService和startService。同样使用活页夹,他们在onStart和onStop期间更新'viewer_connected'和'chat_connected'。
然后服务在执行此操作的线程中运行循环:
public isRunning = true;
while (isRunning) {
if (viewer_connected) {
// send update to viewer activity
}
if (chat_connected) {
// send update to chat activity
}
try {
Thread.sleep(5000);
} catch (Exception e) { isRunning=false; }
// 3 second timeout before destroying service
if (!viewer_connected && !chat_connected) {
try { Thread.sleep(3000); } catch (Exception e) { isRunning=false; }
if (!viewer_connected && !chat_connected) isRunning=false;
}
}
stopSelf();
这是有效的,因为在销毁服务之前,它需要取消绑定的活动和服务stopself(),这意味着在服务被销毁之前存在超时。