Android:旋转显示器时服务被破坏
我有一个在单独进程中运行的服务。我发现主进程 UI 线程从 onDestroy() 退出后,即使我已为应用程序上下文提供了绑定并指定了 BIND_AUTO_CREATE,我的服务仍被销毁。
在我的主进程的 UI 线程 onCreate() 中,我得到了这个绑定代码:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
在我的主进程的 UI 线程 onDestroy() 中,我得到了这个解除绑定代码:
mAppContext.unbindService(mMyServiceConnection);
请注意,我从不调用 stopService()。
Android 的bindService() 文档说:
只要调用上下文存在,系统就会认为该服务需要。
如果我没看错的话,因为我提供了应用程序的上下文,所以该服务被认为是系统在应用程序的生命周期中所需要的。
我认为应用程序的上下文可能会因 onDestroy() 而终止。 Android 文档中对 getApplicationContext() 的描述如下:
返回当前进程的单个全局应用程序对象的上下文。
如果应用程序的上下文因 onDestroy() 而终止,那么我认为 Android 有一个大问题。问题是,当显示器旋转时,会调用 onDestroy()(并立即调用 onCreate())。因此,效果是当显示器旋转时——在我的例子中,这种情况经常发生! -- 我的服务总是退出。
请注意,我的应用程序进程的 pid 永远不会改变,即它是相同的进程。鉴于 getApplicationContext() 的文档指出“当前进程”,这一点很重要。
以下是我的调试日志显示的内容:
04-03 05:15:12.874: 调试/MyApp(841): main onDestroy
04-03 05:15:12.895: 调试/MyApp(847): 解除绑定服务
04-03 05:15:12.895: 调试/MyApp(847): 服务 onDestroy
04-03 05:15:12.934: 调试/MyApp(841): 主要 onCreate
04-03 05:15:12.966:调试/MyApp(847):服务onCreate
04-03 05:15:12.975:调试/MyApp(847):服务onBind
所以我的问题是:
1)我对绑定/解除绑定的理解是否正确?
2)有没有办法让我的服务在调用UI线程的onDestroy()时不被销毁?
问题#2 的一个技巧是永远不要解除绑定。但我不喜欢它,因为每次调用 onDestroy() 时我都会泄漏绑定。我可以“记得”我有一个泄露的绑定,并且只泄露了那个,但随后我遇到了级联黑客攻击,这真的很丑陋。
I've got a service that is running in a separate process. I'm finding that after the main process UI thread exits from onDestroy() that my service is being destroyed even though I've provided the application context with the binding and specified BIND_AUTO_CREATE.
In my main process' UI thread onCreate() I've got this binding code:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
In my main process' UI thread onDestroy() I've got this unbinding code:
mAppContext.unbindService(mMyServiceConnection);
Note that I never call stopService().
Android's documentation for bindService() says:
The service will be considered required by the system only for as long as the calling context exists.
If I'm reading that correctly, because I supplied the application's context, the service is considered required by the system for the life of the application.
I have thought that maybe the application's context dies with onDestroy(). This is what Android's documentation says for getApplicationContext():
Return the context of the single, global Application object of the current process.
If the application's context dies with onDestroy(), then I think Android has a big issue. The issue is that when the display is rotated, onDestroy() is called (and immediately followed by onCreate()). Thus the effect is that when the display is rotated -- and it occurs quite frequently in my case! -- my service always exits.
Note that the pid of my app's process never changes, i.e. it is the same process. That is important in light of the documentation for getApplicationContext() stating "current process."
Here are what my debug logs show:
04-03 05:15:12.874: DEBUG/MyApp(841): main onDestroy
04-03 05:15:12.895: DEBUG/MyApp(847): service 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
So my questions are:
1) Is my understanding about binding/unbinding correct?
2) Is there a way to have my service not get destroyed when UI thread's onDestroy() is called?
A hack for question #2 is to never unbind. But I don't like it because then I am leaking a binding every time onDestroy() is called. I could "remember" that I've got one leaked binding, and leak just that one, but then I've got cascaded hacks and it's real ugly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的服务是否会被终止
Activity
,为什么在您的应用程序被销毁后您需要您的服务保持活动状态?
我认为一般的经验法则是,您无法确定您的活动和服务何时会被终止。如果这阻碍了您想要实现的目标,那么可能有一个聪明的方法可以解决它。
编辑 - 您实际上可以处理方向配置更改,以便您的 Activity 不会重新启动。有关详细信息,请参阅此答案的后半部分。
关于“第二个”
Activity
:想象一下,您启动活动A
,然后启动活动B
。现在,您在显示B
时旋转屏幕,导致B
重新启动。此时A
会重新启动吗?我不确定,但我有一种预感,A
往往会保持活动状态,并在方向更改期间使您的应用程序保持活动状态。如果这就是您的目标,这可能是保持服务活力的另一种策略。Does your service get killed:
Activity
on the stack?Why do you need your service to stay alive after your application has been destroyed?
I think the general rule of thumb is that you can't be sure when your activities and services will be killed. If this is blocking something you're trying to achieve, there may be a clever way around it.
Edit - you can actually handle the orientation configuration change so that your activity isn't restarted. For more info see the second half of this answer.
About the "second"
Activity
: Image you start activityA
and then activityB
. Now you rotate the screen whileB
is showing, causingB
to restart. WillA
be restarted at this point? I'm not sure, but I have a hunch thatA
will tend to stay alive and keep your application alive during the orientation change. This might be another strategy for keeping your service alive if that's what you're aiming for.仅当满足以下两个条件时,服务才会被销毁:
这提供了一个很好的解决方案,而且相当正确且安全!
假设有 2 个活动(本例中为“查看者”和“聊天”)需要服务,如果同时有 bindService 和 startService。他们还使用活页夹在 onStart 和 onStop 期间更新“viewer_connected”和“chat_connected”。
然后,服务在线程中运行一个循环来执行以下操作:
这是有效的,因为它需要在销毁服务之前取消绑定活动和服务 stopself(),这意味着在服务被销毁之前有一个超时。
a service is destroyed only when both of the following are true:
this gives a great solution which is also fairly correct and safe!
say there are 2 activities ('viewer' and 'chat' in this example) that need a service, if both bindService AND startService. Also using the binder they update 'viewer_connected' and 'chat_connected' during onStart and onStop.
Then the service runs a loop in a thread that does this:
This works because it needs both the activities to unbind AND the service to stopself() before it destroys the service, meaning there is a timeout before the service gets destroyed.
1)是的,我认为你的理解是正确的(我说我认为是因为我认为我理解你在说什么;-))。您使用的标志意味着“如果有人尝试绑定到它,则自动启动此服务,并在有人绑定到它时保持它运行,但一旦没有人绑定到它,请随意杀死它”。
2) 查看 此处所述的
START_STICKY
标志。这应该允许您启动服务并保持其运行,无论调用Context
发生什么情况。一般来说,
onDestroy()
意味着您的 Activity 即将被终止。当您旋转显示器时,Activity
将被终止并重新创建。您负责使用适当的方法将任何状态保存到Bundle
,然后在onCreate()
中恢复它。1) Yes, I think your understanding is correct (I say I think because I think I understand what you're saying ;-) ). The flag you are using means "start this service automatically if somebody tries to bind to it and keep it running as long as somebody is bound to it, but once nobody is bound to it, feel free to kill it".
2) Check out the
START_STICKY
flag as described here. That should allow you to start the service and keep it running regardless of what happens to the callingContext
In general,
onDestroy()
means your activity is about to be killed. When you rotate the display, theActivity
is killed and recreated. You are responsible for saving any state to theBundle
in the appropriate method and then restoring it inonCreate()
.