最近版本的 Android 似乎对后台运行服务引入了多项限制,这对于我们设备的电池生命周期来说当然是个好消息。我的目标是创建一个应用程序,只要用户与应用程序交互(这似乎是他们的目标),就仅运行服务来遵守这一点。但我不清楚如何正确实现这一点。我的要求如下:
一旦任何 Activity 对用户可见,就应启动服务。
当用户与应用交互(在 Activity 之间浏览)时,服务应保持不间断运行状态。
当 UI(无论什么 Activity 处于 Activity 状态)发送到后台时,服务应运行 2-3 秒,然后自行停止。彻底关闭服务需要 2-3 秒。
当应用程序处于后台(或关闭)时,可以通过推送消息启动该服务,以便随时处理传入的事件。然后该服务注册到远程服务器并检查更新。如果有更新,则会向用户发出通知。然后,服务在 2-3 秒不活动后再次关闭。
对我来说,似乎应该使用绑定(bind)服务。但我不清楚我的需求如何适应绑定(bind)服务模型。有没有人有这方面的经验,可以指出我正确的方向?
编辑:本例中的“服务”是本地进程内服务,不适合从外部访问。
最佳答案
(此答案假定本地“进程中”服务,这无疑是您打算使用的服务。)
对于您的用例,您实际上使用了多种技术的组合来保持 Service
运行。
使用“绑定(bind)Service
模型”来保持Service
,同时您的任何一个Activity
可见。这很简单;在 Activity.onStart()
中调用 bindService()
,并在 Activity.onStop()
中调用 unbindService()
。如果您担心 Service
在两个 Activity
之间的短暂过渡期间被破坏,请不要担心; Android 足够聪明,可以等待不同应用程序组件的生命周期变化“解决”,然后再决定 Service
未被引用/不需要。
您应该对所有 bindService()
调用使用 BIND_AUTO_CREATE
标志。请记住,Service
并不是在调用 bindService()
后立即创建的;这需要几毫秒的时间,并且您必须小心,通过从当前所在的任何生命周期方法(例如 onStart()
)返回来将控制权返回给框架。只有这样您才会接到电话到onServiceConnected()
。
您需要手动跟踪有多少 Activity
绑定(bind)到您的 Service
,以便确定何时开始 2-3 秒的清理逻辑。请参阅this answer以获得有效的方法。不必担心 Service
在最后一次 unbindService()
调用期间被同步销毁 - 就像实际的生命周期 bindService()
一样状态改变被“延迟”。
现在的问题是,此时(您已确定打开的 Activities< 数量),如何在这额外的 2-3 秒内保持
已降至 0)?那么,您只需调用 Service
处于 Activity 状态startService()
即可。您甚至可以从 Service
子类中的方法调用它;只要您有有效的Context
可用,这并不重要。 startService()
向系统指示您希望保留 Service
,无论可能绑定(bind)多少 Activities
(或其他客户端)到它。在这种情况下,Service
将不会重新启动 - 它已经在运行!
清理完成后,您可以调用 stopService()
,或者更好的是,stopSelf()
。这实际上取消了 startService()
调用,并告诉操作系统“我完成了”。预计此后不久将调用 Service.onDestroy()
。
请记住,您的一个Activity
可能会异步弹出,并在清理完成之前重新绑定(bind)到Service
。这是一种边缘情况,但很容易处理。仅当满足以下两个条件时,Service
才会被销毁:1.) 没有客户端正在绑定(bind)/绑定(bind),并且 2.) 没有未取消的对 startService()
的调用存在。
请注意,在 Oreo 及更高版本上,系统可能会非常积极地杀死具有后台服务
的应用程序。根据this doc ,与用户交互会将您列入白名单“几分钟”,所以我认为 2-3 秒就可以了。同样,如果您正在处理“高优先级 FCM 消息”(我认为您所说的“推送”消息就是这个意思),您将被置于白名单中,并允许另外几分钟执行 Service
(这次使用 startService()/stopSelf()
方法)。
关于Android 服务仅在 UI 处于 Activity 状态时运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54323680/