17

我有一个后台服务,它有时会在内存不足时被操作系统杀死。

  1. 如何模拟这种行为以便我可以调试它?

开发指南简单地说“如果您的服务已启动,那么您必须将其设计为优雅地处理系统重新启动。如果系统终止您的服务,它会在资源再次可用时重新启动它”。

  1. 从它被杀死到它完成重新启动的调用顺序是什么?

在一个侧面(相关)问题上,当服务被操作系统杀死时,服务中启动的主动运行的 AsyncTask 会发生什么,即没有调用 service.onDestroy?它是继续运行还是随着服务默默地被撕掉?

4

3 回答 3

8

在较新的版本下,服务将触发以下事件:

onCreate()

其次是...

int onStartCommand(Intent intent, int flags, int startid)

我知道您在上面的评论中提到使用它,但值得重复:不要使用旧的“onStart()”事件。onStartCommand 是一种新的做事方式。

onCreate() 可用于创建任何对象等,但在 onStartCommand() 中执行您的服务的实际代码。

完成 onStartCommand() 后,您应该返回一个结果。使用“START_STICKY”告诉操作系统如果需要杀死它可以重新启动。使用“START_NOT_STICKY”告诉操作系统不要在内存再次可用后尝试重新启动它。这意味着您的应用程序需要再次手动启动服务。还有其他选项 - 检查 API 文档。

检查这些标志将让您了解您的服务启动的原因- 是您自己的应用程序启动它还是操作系统启动它以重新启动它。您需要定期存储任何重要变量的状态,以便如果操作系统重新启动它,您可以检索这些变量 - 您可能可以使用 SharedPreferences 私有存储来存储这些变量。绝对将任何内容存储在 onDestroy 事件中,但不要指望它会被调用。

此外,建议您将 startID 字段存储在一个变量中,并在您的服务完成运行时将其与 stopSelfResult(startId) 一起使用。

请记住,如果您的服务被操作系统杀死,您可能没有机会存储任何变量。 您需要能够查看您的状态是否在操作系统重新启动时处于您期望的状态,如果不只是重置所有内容,或者可能优雅地死掉。

就调试而言,您是否考虑过编写另一个应用程序,该应用程序除了在 Activity 中吸收内存以强制低内存条件之外什么都不做?顶级活动应该优先考虑内存并强制服务终止。

在服务中启动的其他线程仍然是同一应用程序进程的一部分,因此它们将与服务(以及应用程序的其余部分)一起被杀死。您可以通过在线程中添加常规日志语句然后杀死服务来验证这一点.

其他可能对您有用的东西是检查您的服务是否已经在您的应用程序内部运行。这是一个功能:

// Determine if one of my services is currently running
public static boolean isMyServiceRunning(Context context, String servicename) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (servicename.equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}
于 2012-01-07T20:52:16.210 回答
3

如果它是本地服务(默认),而不是远程服务,那么它与您的应用程序在同一进程中运行。这意味着您可以通过杀死应用程序的进程来模拟杀死它。您可以使用 ddms 来执行此操作,例如在 eclipse 中或从命令行,甚至从您的手机(设置 -> 应用程序)。

于 2011-08-31T21:25:58.073 回答
1

Tony Maro答案的 Kotlin 版本:

@Suppress("DEPRECATION")
fun <T> Context.isServiceRunning(service: Class<T>): Boolean {
    return (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Integer.MAX_VALUE)
        .any { it.service.className == service.name }
}
于 2019-04-23T09:35:26.507 回答