START_STICKY and START_NOT_STICKY

318
4个回答

433

这两个代码只有在手机内存不足并且在服务执行完成之前被杀死时才相关。 START_STICKY 告诉操作系统在有足够内存时重新创建服务,并再次使用空意图调用 onStartCommand()START_NOT_STICKY 告诉操作系统不要重新创建服务。还有第三个代码 START_REDELIVER_INTENT,它告诉操作系统重新创建服务并将相同的意图传递给 onStartCommand()

这篇由 Dianne Hackborn 撰写的文章比官方文档更好地解释了背景。

来源:http://android-developers.blogspot.com.au/2010/02/service-api-changes-starting-with.html

这里的关键部分是函数返回的新结果代码,告诉系统如果在运行时其进程被杀死,应该如何处理服务:

START_STICKY 基本上与以前的行为相同,即服务保持“启动”状态,并稍后由系统重新启动。与平台先前版本唯一的区别是,如果因为其进程被杀死而重新启动,则下一个服务实例上的 onStartCommand() 将使用空意图调用,而不是根本不被调用。使用此模式的服务应始终检查此情况并适当处理。

START_NOT_STICKY 表示在从 onStartCreated() 返回后,如果进程被杀死且没有剩余的启动命令要传递,则服务将停止而不是重新启动。这对于只在执行发送给它们的命令时运行的服务更有意义。例如,可以从闹钟每 15 分钟启动一次服务以轮询某些网络状态。如果在执行该工作时被杀死,最好就让它停止,并在下次闹钟触发时重新启动。

START_REDELIVER_INTENT类似于START_NOT_STICKY,但是如果服务的进程在为给定意图(intent)调用stopSelf()之前被杀死,那么该意图将被重新传递(re-delivered)直到完成(除非经过多次尝试后仍然无法完成,在这种情况下,系统会放弃)。

这对于接收要做的工作命令并希望确保它们最终完成每个发送的命令的服务非常有用。


1
如何避免重复调用任务handleStart(intent, startId)?因为onStart()和onStartCommand都会被调用,这是一个好的设计吗?@Frank Leigh - Sazzad Hissain Khan
2
如果没有指定任何标志,那么默认标志是什么? - IgorGanapolsky
3
如果你跟随“return super.onStartCommand(...);”,你会发现如果你的目标SDK版本低于ECLAIR(API5=2.0),默认情况下返回START_STICKY_COMPATIBILITY,而从2.0及以上版本则返回START_STICKY。 - MikeL
1
@FrankLeigh 排队了吗?怎么排队?我的意思是,如果它是IntentService(在IntentService的工作线程的事件队列中),那肯定是排队了,但如果它不是IntentService呢?你是指主线程的事件队列吗? - stdout
3
@FrankLeigh,我不同意START_REDELIVER_INTENT类似于START_NOT_STICKY的说法。相反,它更像是START_STICKY - CopsOnRoad
显示剩余7条评论

131

KISS 原则

区别:

START_STICKY

系统将尝试在服务被杀死后重新创建它。

START_NOT_STICKY

系统不会在服务被杀死后尝试重新创建它。


标准示例:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY;
}

7
这实际上是不正确和令人困惑的。说“服务被杀死”是一个错误,因为有些人可能会认为你指的是stopSelf或stopService,而你显然是指进程被杀死。所以在你的回答中最好使用“进程”这个词。 - Ilya Gazman
你好,我该如何测试START_REDELIVER_INTENT?我刚刚测试了START_STICKY并通过最近使用的应用程序杀死了应用程序。然后它重新调用了服务。但是START_REDELIVER_INTENT再也没有被调用了。为什么? - Asif Mushtaq
@IlyaGazman 我恭敬地不同意。Stopped和killed是两个非常不同的词。这个答案以简单明了的方式正确解释了这个问题。 - NoHarmDan

27

START_STICKYSTART_NOT_STICKY的文档说明非常简明。

START_STICKY:

如果这个服务的进程在它启动后(从 onStartCommand(Intent, int, int)) 返回后)被杀死了,那么保持它处于已启动状态,但不保留此传递的 intent。稍后系统将尝试重新创建该服务。因为它处于已启动状态,所以在创建新的服务实例后保证会调用 onStartCommand(Intent, int, int);如果没有任何待处理的启动命令要传递到服务,则会使用 null intent 对象调用它,因此您必须注意检查此情况。

此模式对于那些将显式启动和停止以运行任意时间段的任务(例如执行后台音乐播放的服务)是有意义的。

示例:本地服务示例

START_NOT_STICKY:

如果这个服务的进程在它启动后(从 onStartCommand(Intent, int, int)) 返回后)被杀死了,并且没有新的启动 intent 要传递给它,那么将该服务从已启动状态中移除,并且在未来进行显式调用 Context.startService(Intent)之前不会重新创建。服务不会收到带有 null Intent 的 onStartCommand(Intent, int, int)调用,因为如果没有待处理的 Intent,则不会重新启动它。

此模式对于想要作为结果执行某些工作(例如下载文件)并且不需要保持运行状态的任务是有意义的。

虽然这种服务被启动,但当内存压力过大时可以停止,并且稍后会自动重新开始工作。这样一个服务的例子是从服务器中轮询数据的服务:它可以通过启动闹钟来调度每隔N分钟轮询的时间。当服务从闹钟调用其 onStartCommand(Intent, int, int) 方法时,它会为N分钟后安排一个新的闹钟,并生成一个线程进行网络操作。如果在此检查期间杀死了该进程,则在闹钟响起之前不会重新启动服务。

示例:ServiceStartArguments.java


1
很遗憾,伙计们。我无法用通俗易懂的语言解释文档。我想用实时场景来解释。我想在设备上展示一个例子,这样他们就可以更容易地理解了。 - prago
对于START_STICKY和START_NOT_STICKY,onStartCommand()只会被执行一次并退出。我已经查看了您指出的示例,但我的疑问是onStartCommand()会被执行多少次。如果我返回START_STICKY并尝试重新创建服务,服务是否会再次执行onStartCommand()? - prago
当服务被重新创建时,活动会发生什么?活动也会被重新创建吗? - ransh
我想我们永远也不会知道。 - Denny

5
  • START_STICKY: 如果服务终止且传递给onStartCommand()方法的Intent数据为NULL,则将重新启动该服务。这适用于不执行命令但独立运行并等待作业的服务。
  • START_NOT_STICKY:它不会重新启动服务,并且对于定期运行的服务非常有用。只有在存在未决 startService()调用时,服务才会重新启动。这是避免在不必要时运行服务的最佳选项。
  • START_REDELIVER_INTENT:它与STAR_STICKY相同,并重新创建服务,使用上次传递给服务的Intent调用onStartCommand()

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