原文:
https://blog.csdn.net/taki_dsm/article/details/8865913
https://blog.csdn.net/imxiangzi/article/details/76039978
返回值
继承Service类来实现一个被启动类型的服务很简单,如果你需要服务执行多线程(而不是通过工作队列来处理启动请求),那么你就要继承Service类来处理每个Intent。
继承Service类,onStartCommand()执行后,业务代码马上同时执行,不像IntentService那样以队列排队执行。
但是,因为你自己处理每个onStartCommand()方法的调用,你就能够同时执行多个请求。如果你想要这么做的话,那么你就能够给每个请求创建一个新的线程,并且立即运行它们(而不是等待前一个请求完成)。
注意:onStartCommand()方法必须返回一个整数,这个整数是一个描述了在系统的杀死事件中,系统应该如何继续这个服务的值(虽然你能够修改这个值,但是IntentService处理还是为你提供了默认实现)。从onStartCommand()方法中返回的值必须是以下常量:
public static final int START_STICKY_COMPATIBILITY = 0;
public static final int START_STICKY = 1;
public static final int START_NOT_STICKY = 2;
public static final int START_REDELIVER_INTENT = 3;
START_STICKY
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,那么这个Service会被保留在已开始的状态,但是不保留传入的Intent,随后系统会尝试重新创建此Service,由于服务状态保留在已开始状态,所以创建服务后一定会调用onStartCommand方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null,需要我们小心处理。
这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。比如一个用来播放背景音乐功能的Service就适合返回该值。
START_NOT_STICKY
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,则系统不会重新启动此Service。
举个例子,某个Service需要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据。当执行到Service的onStartCommand时,在该方法内再规划一个N分钟后的定时器用于再次启动该Service并开辟一个新的线程去执行网络操作。假设Service在从服务器获取最新数据的过程中被Android系统强制杀掉,Service不会再重新创建,这也没关系,因为再过N分钟定时器就会再次启动该Service并重新获取数据。
START_REDELIVER_INTENT
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,则结果和START_STICKY一样,也会重新创建此Service并调用onStartCommand方法。不同之处在于,如果是返回的是START_REDELIVER_INTENT ,则重新创建Service时onStartCommand方法会传入之前的intent。(从名字上就可以理解,REDELIVER INTENT,重新提交intent)
这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
START_STICKY_COMPATIBILITY
这个比较简单,是START_STICKY的兼容版本,但是不能保证被清理后onStartCommand方法一定会被重新调用。
Service中默认返回START_STICKY(API5以上)
/**
*Service.java
**/
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
IntentService中默认返回START_NOT_STICKY
/**
*IntentService.java
**/
private boolean mRedelivery;
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
参数
intent
启动时,启动组件传递过来的Intent,如Activity可利用Intent封装所需要的参数并传递给Service。
flags
表示启动请求时是否有额外数据,flags有三个可以传入的值:
0,START_FLAG_REDELIVERY和START_FLAG_RETRY。
- 0
在正常创建Service的情况下,onStartCommand传入的flags为0。
- START_FLAG_REDELIVERY
/**
* This flag is set in {@link #onStartCommand} if the Intent is a
* re-delivery of a previously delivered intent, because the service
* had previously returned {@link #START_REDELIVER_INTENT} but had been
* killed before calling {@link #stopSelf(int)} for that Intent.
*/
public static final int START_FLAG_REDELIVERY = 0x0001;
如果onStartCommand返回的是START_REDELIVER_INTENT,并且Service被系统清理掉了,那么重新创建Service,调用onStartCommand的时候,传入的intent不为null,而传入的flags就是START_FLAG_REDELIVERY 。
- START_FLAG_RETRY
/**
* This flag is set in {@link #onStartCommand} if the Intent is a
* retry because the original attempt never got to or returned from
* {@link #onStartCommand(Intent, int, int)}.
*/
public static final int START_FLAG_RETRY = 0x0002;
如果Service创建过程中,onStartCommand方法未被调用或者没有正常返回的异常情况下, 再次尝试创建,传入的flags就为START_FLAG_RETRY 。
startId:
* @param startId A unique integer representing this specific request to
* start. Use with {@link #stopSelfResult(int)}.
传入的这个startId 用来代表这个唯一的启动请求。我们可以在stopSelfResult(int startId)中传入这个startId,用来终止Service。
那么stopSelfResult(int startId)和通过stopService方法来终止Service有何不同呢?看源码stopSelfResult方法的注释:
* Stop the service if the most recent time it was started was
* <var>startId</var>. This is the same as calling {@link
* android.content.Context#stopService} for this particular service but allows you to
* safely avoid stopping if there is a start request from a client that you
* haven't yet seen in {@link #onStart}.
- stopSelfResult方法传入的startId,必须是最后一次启动Service时传入的startId,才能终止Service。万一我们想终止Service的时候又来了个启动请求,这时候是不应该终止的,而我们还没拿到最新请求的startId,
- 如果用stopService的话就直接终止了,而用stopSelfResult方法就会及时避免终止。
网友评论