美文网首页
IntentService

IntentService

作者: 呆呆李宇杰 | 来源:发表于2017-06-21 18:01 被阅读97次

    IntentService

    简介

    IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,因此必须创建它的子类才能去使用IntentService,IntentService可以用于执行后台耗时任务,而当任务执行完毕会自动停止,同时由于IntentService本身是Service的原因,所以其优先级是单纯的线程高很多,所以IntentService适合用于执行一些高优先级的后台任务。
      在代码的实现上,IntentService封装了HandlerThread和Handler,在onCreate方法的代码中可以得知。

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.
    
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    

    当IntentService被第一次启动时,它的onCreate方法会被调用,onCreate方法会创建HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行,从这个角度看,IntentService也可以用于执行后台任务,每次启动IntentService,它的onStartCommand方法就会调用一次,IntentService在onStartCommand中处理每一个后台任务的Intent。
      从IntentService的onStartCommand方法中可以看出处理外界Intent的逻辑,代码如下。

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    

    从代码的实现可以看出,在OnStartCommand方法中,IntentServide通过构造Message对象,并设置obj为传入的intent,通过mServiceHandler发送信息,而这个信息会被HandlerThread中被处理。这个Intent对象的内容和外界startIntent(intent)中传入的intend对象的内容是完全一致的,并通过这个intent可以解析出外界启动IntentService所传入的参数,从而在onHandleIntent方法中处理。当onHandleIntent方法执行结束后,IntentService会通过stopSelf(int startId)方法来停止服务。

    这里使用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立刻停止服务,这个时候可能会有其他消息还没被处理,而stopSelf(int startId)则会等待所有的信息都处理完毕后才终止服务,一般来说,stopSelf(int startId)在尝试定制服务之前会判断最近启动服务的id是否和startId相等,如果相等则立刻停止服务,否则不停止,在源码中的mActivityManager.stopServiceToken可以找到实现的策略。
      ServiceHandler的实现如下。

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
    
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }
    

    IntentService的onHandleIntent是一个抽象方法,它需要我们在子类中进行实现,它的作用是处理Intent参数并执行任务。如果当前只有一个后台任务,那么onHandleIntent在执行这个任务后,stopSelf(int startId)会立刻停止任务。如果当前存在多个任务,那么当onHandleIntent执行完最后一个任务后,stopSelf(int startId)才会停止任务。另外由于每执行一个后台任务就必须启动一次IntentService,而IntentService内部是通过消息的方式来向HandlerThread请求执行任务的,而Handler中的Looper是顺序处理消息的,所以可以得出,IntentService也是顺序执行后台任务的,所以当有多个后台任务同时存在的时候,这些后台任务会按照外界发起的顺序排队执行。

    示例

    public class LocalIntentService extends IntentService {
    
        private static final String TAG = "LocalIntentService";
    
        public LocalIntentService(String name) {
            super(TAG);
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            String action = intent.getStringExtra("task_action");
            Log.d(TAG, "receive task: " + action);
            SystemClock.sleep(3000);
            if ("TASK1".equals(action)) {
                Log.d(TAG, "handle task: " + action);
            }
        }
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "service destory.");
            super.onDestroy();
        }
    }
    

    上面的代码中,在onHandleIntent中会对Intent中获取参数,然后根据不同的参数去执行不同的后台任务,而SystemClock.sleep(3000);用于模拟耗时的方法,并在onDestory中打印日志,以验证IntentService停止的时机。下面是发起后台任务请求的代码。

    for (int i = 0; i < 3; i++) {
        Intent intent = new Intent(this, LocalIntentService.class);
        intent.putExtra("task_action", "TASK" + (i + 1));
        startService(intent);
    }
    

    以上的代码启动了三次LocalIntentService并传入不同的参数,日志如下所示。

    06-21 17:58:16.681 27761-27805/com.daijie.intentserviceapp D/LocalIntentService: receive task: TASK1
    06-21 17:58:19.682 27761-27805/com.daijie.intentserviceapp D/LocalIntentService: handle task: TASK1
    06-21 17:58:19.683 27761-27805/com.daijie.intentserviceapp D/LocalIntentService: receive task: TASK2
    06-21 17:58:22.684 27761-27805/com.daijie.intentserviceapp D/LocalIntentService: receive task: TASK3
    06-21 17:58:25.686 27761-27761/com.daijie.intentserviceapp D/LocalIntentService: service destory.  
    

    从日志中可以看出,这三个后台任务是排队执行的,执行顺序根据他们发起请求时候的顺序,即TASK1->TASK2->TASK3,并且TASK3执行完后,LocalIntentService的onDestory被回调,服务被停止。

    相关文章

      网友评论

          本文标题:IntentService

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