美文网首页
记录-IntentService源码分析

记录-IntentService源码分析

作者: Manza | 来源:发表于2020-06-06 00:42 被阅读0次

    1.为什么要使用IntentService?

    前提条件是你想使用Service同时又想在Service做一些耗时操作或异步任务处理,这时,使用IntentService比较合适,相较于Service,你不用在Service中重新创建线程,同时你也不用考虑不使用它的时候去调用stopService()方法,下面会讲到这一点。

    2.IntentService的定义

     * IntentService is a base class for {@link Service}s that handle asynchronous
     * requests (expressed as {@link Intent}s) on demand.  Clients send requests
     * through {@link android.content.Context#startService(Intent)} calls; the
     * service is started as needed, handles each Intent in turn using a worker
     * thread, and stops itself when it runs out of work.
    

    上面文字的大意就是,IntentService是Service类根据需要处理异步请求(通常用Intent表示)的基类。客户端通过Context的startService(Intent)方法来发送请求。Service根据需要启动,它是通过一个工作线程并按照顺序来处理每个Intent,当执行完所有任务后会stop self(通过调用stopSelf()方法终止服务)。

    3.IntentService源码分析

    在开始分析源码之前,简单的总结一下我理解的IntentSercice:IntentSercie就是一个可以处理异步任务的Service,内部维护了自己的ServiceHandler和HandlerThread用于消息的传递,并在处理任务结束后自动结束自己的生命周期。
    下面我们开始分析它的源码(package android.app;)

    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        @UnsupportedAppUsage
        private volatile ServiceHandler mServiceHandler;
        private String mName;
        private boolean mRedelivery;
    
        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);
            }
        }
    
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         *
         * @param name Used to name the worker thread, important only for debugging.
         */
        public IntentService(String name) {
            super();
            mName = name;
        }
    
        /**
         * Sets intent redelivery preferences.  Usually called from the constructor
         * with your preferred semantics.
         *
         * <p>If enabled is true,
         * {@link #onStartCommand(Intent, int, int)} will return
         * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
         * {@link #onHandleIntent(Intent)} returns, the process will be restarted
         * and the intent redelivered.  If multiple Intents have been sent, only
         * the most recent one is guaranteed to be redelivered.
         *
         * <p>If enabled is false (the default),
         * {@link #onStartCommand(Intent, int, int)} will return
         * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
         * dies along with it.
         */
        public void setIntentRedelivery(boolean enabled) {
            mRedelivery = enabled;
        }
    
        @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);
        }
    
        @Override
        public void onStart(@Nullable Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
    
        /**
         * You should not override this method for your IntentService. Instead,
         * override {@link #onHandleIntent}, which the system calls when the IntentService
         * receives a start request.
         * @see android.app.Service#onStartCommand
         */
        @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 onDestroy() {
            mServiceLooper.quit();
        }
    
        /**
         * Unless you provide binding for your service, you don't need to implement this
         * method, because the default implementation returns null.
         * @see android.app.Service#onBind
         */
        @Override
        @Nullable
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        /**
         * This method is invoked on the worker thread with a request to process.
         * Only one Intent is processed at a time, but the processing happens on a
         * worker thread that runs independently from other application logic.
         * So, if this code takes a long time, it will hold up other requests to
         * the same IntentService, but it will not hold up anything else.
         * When all requests have been handled, the IntentService stops itself,
         * so you should not call {@link #stopSelf}.
         *
         * @param intent The value passed to {@link
         *               android.content.Context#startService(Intent)}.
         *               This may be null if the service is being restarted after
         *               its process has gone away; see
         *               {@link android.app.Service#onStartCommand}
         *               for details.
         */
        @WorkerThread
        protected abstract void onHandleIntent(@Nullable Intent intent);
    }
    

    IntentService的启动方式和Service是一样的,通常我们使用startService(intent)来启动它。启动IntentService,会依次执行onCreate()->onStartCommand()->onStart()(onStart方法在Service中已经标记为弃用,IntentService重写了该方法,并在onStartCommand中被调用)方法。
    首先我们看下OnCreate()方法源码

    image.png

    可以看到,服务启动后,首先做了一些对于IntentService来说初始化的工作,IntentService之所以可以用来处理异步任务就是由于它内部的ServiceHandler和HandlerThread。上面的代码首先实例化了一个HandlerThread线程(源码这里暂不赘述,有兴趣的话可以看看我的另外一篇文章记录-HandlerThread源码分析
    ,并通过start()方法来启动该线程。之后通过thread获取到该线程的Looper对象来实例化一个ServiceHandler。
    然后我们再看onStartCommand()方法源码

    image.png

    注释的大意是:你不应该在你的IntentService中重写该方法,相反,应该在你自己定义的IntentService中重写onHandleIntent()方法,onHandleIntent方法会在收到启动请求时由系统调用。可以看到该方法中调用了onStart()方法,并且把intent,startId传递过去。
    接着看onStart()方法


    image.png

    在onStart方法中,通过我们在onCreate()中实例化的ServiceHandler对象在消息池中获取一个消息对象,并把该对象设置给message的target属性(感兴趣的可以看下,通过这种方法生成message可以复用消息池中的对象而不必新建,同时又可以直接把handler对象赋值给message的target属性,在Looper.loop()方法中会用到,此处不赘述),然后通过mServiceHandler的sendMessage方法发送消息。
    接下来我们看ServiceHandler的源码

    image.png

    可以看到handler在收到消息后,做了两件事儿,第一,调用onHandleIntent方法,该方法在IntentService中是一个抽象方法,需要我们的子类自己实现,我们可以在该方法中做一些耗时操作(不必另外开启线程,因为当前该方法就是在上面讲到的HandlerThread中执行的);第二,在执行完onHandleIntent()方法后,IntentService调用了自己的stopSelf()方法来结束自己的生命周期。stopSelf()方法和我们在activity中调用stopService方法一样,都会触发Service的OnDestroy()方法。大家可能注意到,stopSelf方法有个startId的参数,需要注意的是startId必须配对,stopSelf()才会停止服务。

    4.常见问题

    4.1可以在onHandleIntent()方法中进行异步操作吗?

    onHandleIntent()方法本身就是在子线程中执行的,如果在此方法中再执行异步任务,由于onHandleIntent执行完成之后会调用stopSelf()方法,此方法会结束掉当前的IntentService,同时在IntentService的onDestroy方法中mServiceHandler会执行quit()方法,所以导致异步代码的结果无法接收到。

    4.2.可以使用bindService()来启动IntentService吗?

    image

    这是一张Service在不同启动方式下的生命周期图,我们可以看到通过bindService()来启动并不会调用onStartCommand()方法,IntentService中维护的mServiceHandler也就无法发送消息进而onHandleIntent()方法也不会再调用,所以也就和使用普通的Service没有区别了。

    4.3.多次启动IntentService会发发生什么?停止服务后,后续的事件还会不会执行?

    mServiceHandler是在onCreate中创建的,在Service中,无论是何种启动方式,此方法在整个生命周期中只会执行一次,所以,HandlerThread和ServiceHandler都只实例化了一次,相反,每次启动都会调用onStartCommand()方法,然后把消息加入到消息队列中进行等待并按顺序执行。问题5中已经说到,停止服务后在onDestroy方法中会调用mServiceHandler的quit()方法,导致后续事件无法执行。

    相关文章

      网友评论

          本文标题:记录-IntentService源码分析

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