IntentService意图服务 源码解读

基本概念

IntentService作用

IntentService是Service类的子类,常用来在后台执行耗时的异步请求。我们不用去关心Service的创建和销毁的细节。也不用单独开线程,只管处理自己的任务,处理完过后系统会自动销毁该服务,启动IntentService的方式和普通Service相同,但是使用起来却极其简单。使用示例如下:

//自定义一个IntentService
public class MyService extends IntentService {

    public MyService() {
        super("MyService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
         String url=intent.getStringExtra("url");
         //在这处理你的任务
          //...
    }
}


//启动IntentService
  Intent intent=  new Intent(this,MyService.class);
  intent.putExtra("url","......");
  startService(intent);

IntentService疑问

看完上面的基本概念后,你可能会产生如下疑问。

  • IntentService构造方法传的那个参数是来干嘛的
  • IntentService内部是怎么工作的?
  • IntentService怎么做到任务结束后自动销毁?

让我们带着疑问,再次去源码里探索吧。

初识API

HandlerThread

初看这个名字,心里在想,难道是内部自带Handler的线程?笔者怀着好奇的心,点开了HandlerThread这个类。因为HandlerThread继承于Thread,于是反射性的找到了run方法里面的源码进行研究,源码如下:

     @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//初始化Looper

        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);

        onLooperPrepared();
        Looper.loop();//开启Looper无限循环
        mTid = -1;//这句话永远执行不到,除非Looper被退出
    }

果然如此,很常规的Looper初始化。有Looper,肯定会有Handler,不然Looper岂不是浪费了。但是在Looper.prepare();Looper.loop()之间,并没有看到Handler的踪影。笔者心想,莫非谷歌用了什么黑科技用法,于是快速把源码过了一遍。WTF!Handler呢?并没有找到啊。既然没有,干嘛叫HandlerThread,这名字取的只给1分。于是查看了API说明。说明如下:

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
大意:这个类用于创建一个拥有Looper的线程。这个Looper可以用来创建Handler类,虽然如此,start()仍然必须调用。

看到这里算是明白了,原来这个线程只是用来提供Looper的啊,以免我们在子线程中使用Handler过于麻烦。必须调用start是因为,Looper的初始化在run方法内。使用示例如下:

//启动带Looper的线程
 HandlerThread handlerThread=new HandlerThread("handlerThread");
 handlerThread.start();

 //初始化Handler
 Handler handler=new Handler(handlerThread.getLooper()){
            @Override
     public void handleMessage(Message msg) {
               // 在这里接收消息,这里的处理是在子线程中执行的。
            }
        };

 handler.sendMessage(..)//发送消息

笔者心想,由于线程的不稳定性,handlerThread.getLooper()会不会取到个空值啊。点进去一看,瞬间觉得自己想多了。可以看到,如果为空就将线程挂起等待,即时你手动唤醒,还有个while循环进行保障。

    public Looper getLooper() {
        //...
        //省略部分源码
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

当Looper初始化完毕,就会唤醒等待的线程,唤醒方法就在run方法中。

 public void run() {
        //...
        //省略部分源码
        Looper.prepare();//初始化Looper

        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();//唤醒等待线程
        }
        //...
        //省略部分源码
        Looper.loop();//开启Looper无限循环

    }

可以看出handlerThread.getLooper()是个阻塞方法。

工作原理

IntentService的用法,前面已经介绍过了,现在开始来梳理流程。
我们知道,只需在onHandleIntent里面编写耗时任务,系统就会自动开启线程去处理,处理完毕后,自动销毁Service。这一过程,尤其显得格外人性化。

那么,IntentService内部流程是怎么样的?IntentService继承与Service,那我们就按照Service的生命周期来一步一步进行探索,由于源码比较简单,这里就快速过一遍。

onCreate

    @Override
    public void onCreate() {
        super.onCreate();
        //启动带Looper的线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

       //初始化Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

可以看出,用了HandlerThread,同时也初始化了一个Handler。看完这里。我想你心里一定有谱了。大约明白了内部工作原理。通过HandlerThread,利用Handler发送消息转移到子线程中,然后处理任务。

onStartCommand

为了验证我们的猜想。继续阅读源码,找到onStartCommand

 @Override
public int onStartCommand(Intent intent, int flags, int startId) {

        onStart(intent, startId);

        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

可以看出,内部调用了onStart

 @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

onStart内部,终于验证了我们的猜想。将intentstartId,发送到了子线程中。于是我们找到Handler内部的handleMessage方法一探究竟。

Handler内部的handleMessage

  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);
        }
    }

看到这里,终于明白了onHandleIntent为什么不需再开线程。也明白了为什么可以自动销毁Service。
但是,机智的你可能心里在嘀咕。那个HandlerThread呢?里面是个死循环,不能自动停止,一直占有着资源怎么办?那么。我们再来看一下Service的最后一个生命周期。

onDestroy

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

可以看出,在销毁的同时也退出了Looper循环。

最后

  • IntentService构造方法传的那个参数是来干嘛的
    我们先来看一下IntentService的构造函数。可以看出最终传给了HandlerThread。而给Thread传一个名字更加便于调试,不然线程的默认名是"Thread-" + id;,不方便调试。
    public IntentService(String name) {
        super();
        mName = name;
    }


       @Override
    public void onCreate() {
        //..
        //省略了部分源码
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        //..
        //省略了部分源码

    }
  • 为什么不在onHandleIntent中退出Looper?
    那是因为跟普通Service一样,IntentService也可以启动多次。如果在结束服务之前又有新任务提交过来了,stopSelf(int startId)并不能结束服务。因为startId必须与最后一次启动相同时才会结束服务。所以在onDestory中退出更加合适。

总结

可以看出在IntentService的内部又出现了Handler的身影,Handler在Android中的地位不言而喻,对于Handler不太了解的,可以参考这篇 Handler消息机制 源码解读

发布了30 篇原创文章 · 获赞 287 · 访问量 43万+

猜你喜欢

转载自blog.csdn.net/maplejaw_/article/details/51479174