天天看點

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 = -;//這句話永遠執行不到,除非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

内部,終于驗證了我們的猜想。将

intent

startId

,發送到了子線程中。于是我們找到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消息機制 源碼解讀。