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消息機制 源碼解讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章