如何强制重启一个服务?

17

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

  1. 如何模拟这种行为以便进行调试?

开发指南简单地说:“如果您的服务已启动,则必须设计它以通过系统的优雅重启来处理。如果系统杀死您的服务,它会在资源再次可用时立即重新启动它。”

  1. 当服务被杀死到完成重启时的调用顺序是什么?

另外一个相关的问题是,在服务被操作系统杀死时(即在服务.onDestroy被调用之前),在服务中启动的活动运行的AsyncTask会发生什么?它会继续运行还是与服务一起被静默地关闭?

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中仅执行内存占用以强制发生低内存条件吗?顶部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;
}

DDMS中的终止(正如yjw所提到的)会使我获得重启行为。感谢您详尽的解释。 - Eric Chen
DDMS的技巧很好,解释也没问题。恰好我刚写了一个条形码扫描应用程序,将所有工作都作为服务运行,这样屏幕就不需要开启。 - Tony Maro

3
如果是本地服务(默认值),而不是远程服务,则它与您的应用程序在同一进程中运行。这意味着您可以模拟通过终止应用程序进程来杀死它。例如,您可以使用Eclipse中的DDMS或从命令行甚至从手机(设置->应用程序)来完成此操作。请注意,保留HTML标记。

1
我可以执行杀死操作,但是没有与之相关的重新启动。 - Eric Chen
检查您从Service的onStartCommand返回的值。我认为这是您想要的:http://developer.android.com/reference/android/app/Service.html#START_STICKY - Erdal
是的,那是我正在使用的。我主要的问题是我不知道如何模拟Android杀死-重启服务的行为。 - Eric Chen
2
有点晚了,但你还在遇到这个问题吗?我编写了一个简单的服务,在其中记录了onCreate、onStartCommand和onDestroy,并使用START_STICKY标志。我注意到,如果我使用DDMS终止进程,我的服务实际上会被重新创建(如文档中所述,在onStartCommand中Intent = null)。但如果我使用“设置”->“应用程序”,它就不起作用了。 - yjw
相关链接:https://dev59.com/4FwX5IYBdhLWcg3wtBXG - Mr-IDE

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接