美文网首页
Service类onStartCommand()详解

Service类onStartCommand()详解

作者: 空山Echo | 来源:发表于2019-05-08 10:38 被阅读0次

    原文:
    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方法就会及时避免终止。

    相关文章

      网友评论

          本文标题:Service类onStartCommand()详解

          本文链接:https://www.haomeiwen.com/subject/rznroqtx.html