如何强制重启服务?

时间:2011-08-31 13:11:53

标签: android service restart kill-process low-memory

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

  1. 如何模拟此行为以便我可以调试它?
  2. 开发指南简单地说“如果您的服务已启动,那么您必须将其设计为优雅地处理系统重新启动。如果系统终止您的服务,它会在资源再次可用时立即重新启动”。

    1. 从被杀死到完成重启时的调用顺序是什么?
    2. 在一个(相关的)问题上,当服务被操作系统杀死时,在服务中启动的主动运行的AsyncTask会发生什么情况,即没有调用service.onDestroy?它是否继续运行或与服务一起静静地撕开?

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:3)

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

答案 2 :(得分:0)

Tony Maro的答案的科特林版本:

@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 }
}