Android 服务 运行 仅当 UI 处于活动状态时

Android Service Running only when UI is active

似乎 Android 在最近的版本中引入了对后台 运行ning 服务的多重限制,这当然对我们设备的电池寿命来说是个好消息。我的目标是创建一个应用程序,只要用户与应用程序交互(这似乎是他们的目标),就只需要 运行 提供服务即可。但我不清楚如何正确实施它。我的要求如下:

对我来说,绑定服务似乎就是要使用的。但我不清楚我的要求如何适合绑定服务模型。有没有人有这方面的经验,谁能给我指明正确的方向?

编辑:本例中的 "Service" 是本地进程内服务,不打算从外部访问。

(这个答案假设一个本地的,"in-process" Service,这无疑是你打算使用的。)

对于您的用例,您实际上使用了多种技术的组合来保持 Service 运行。

使用 "bound Service model" 保持 Service 在您的任何一个 Activities 可见的情况下。这很简单;在 Activity.onStart() 中调用 bindService(),在 Activity.onStop() 中调用 unbindService()。如果您担心 Service 在两个 Activities 之间的短暂过渡时刻被破坏,请不要担心; Android 足够聪明,可以等待不同应用程序组件的生命周期更改为 "settle",然后再决定 Service 是 unreferenced/unneeded。

您应该为所有 bindService() 调用使用 BIND_AUTO_CREATE 标志。请记住 Service 并不是在调用 bindService() 时立即创建的;它需要几毫秒,你必须小心 return 控制框架,通过 returning 从你当前所在的任何生命周期方法(例如,onStart())。只有这样你接到 onServiceConnected().

的电话

您需要手动跟踪有多少 Activities 绑定到您的 Service,以确定何时开始您的 2-3 秒清理逻辑。有关有效方法,请参阅 this answer。不要担心 Service 在上次 unbindService() 调用期间被同步销毁——就像 bindService() 一样,实际的生命周期状态变化是 "delayed."

现在的问题是,如何让 Service 在这额外的 2-3 秒内保持活动状态,此时(您确定打开 Activities 的数量已下降到 0)?那么,您可以简单地调用 startService()。您甚至可以从 Service 子类中的方法调用它;只要您有可用的有效 Context,这并不重要。 startService() 向系统表明您希望保留 Service,而不管有多少 Activities(或其他客户端)可能绑定到它。在这种情况下,Service 不会重新启动——它已经是 运行!

清理完成后,您可以调用 stopService(),或者更好的是,调用 stopSelf()。这有效地取消了 startService() 调用,并告诉 OS、"I'm done"。预计此后不久将致电 Service.onDestroy()

请记住,您的 Activities 之一可能会异步弹出,并在清理完成之前重新绑定到 Service。这是一种边缘情况,但很容易处理。 Service 只有在以下两个条件都为真时才会被销毁:1.) 没有客户端是 binding/bound,以及 2.) 不存在对 startService() 的未取消调用。

请注意,在 Oreo 及更高版本上,系统可能会非常积极地终止具有背景的应用程序 Services。根据 this doc,与用户交互会使您进入 "several minutes" 的白名单,所以我认为 2-3 秒就可以了。类似地,如果您正在处理 "high-priority FCM message"(我假设您的意思是 "push" 消息),您将被列入白名单,并允许再花几分钟时间执行 Service(这次使用 startService()/stopSelf() 方法)。