從源碼分析IntentService

無論學什麼知識點最好從其基本用法開始,而後在深刻到源碼層學習會比較容易理解源碼帶給咱們的思想。因此我們先來看看IntentService的基本用法。java

其實很簡單,遵照必定的套路就能夠設計模式

  1. 繼承IntentService並生成構造方法經過super()來完成父類的基本初始化操做
  2. 重寫父類的onHandleIntent方法並執行須要完成的後臺任務操做(上傳文件等)
  3. 重寫onDestroy來完成些清理工做

好比:安全

public class MyIntentService extends IntentService {
        private static final String ACTION_BAZ = "com.example.comp.action.BAZ";

        private static final String EXTRA_PARAM1 = "com.example.comp.extra.PARAM1";
        private static final String EXTRA_PARAM2 = "com.example.comp.extra.PARAM2";

        public MyIntentService() {
            super("MyIntentService");
            setIntentRedelivery(false);
        }
        //用於啓動此服務的輔助方法
        public static void startActionBaz(Context context, String param1, String param2) {
            Intent intent = new Intent(context, MyIntentService.class);
            intent.setAction(ACTION_BAZ);
            intent.putExtra(EXTRA_PARAM1, param1);
            intent.putExtra(EXTRA_PARAM2, param2);
            context.startService(intent);
            Log.d("MyIntentService","startActionBaz");
            Log.d("MyIntentService","threadID:" + Thread.currentThread().getId());
        }

        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d("MyIntentService","onHandleIntent:" + Thread.currentThread().getId());
            if (intent != null) {
                final String action = intent.getAction();
                if (ACTION_BAZ.equals(action)) {
                    final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                    final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                    handleActionBaz(param1, param2);
                }
            }
        }

        private void handleActionBaz(String param1, String param2) {
            Log.d("MyIntentService","handleActionBaz:" + Thread.currentThread().getId());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d("MyIntentService","onDestroy:" + Thread.currentThread().getId());
        }
    }

在前臺activity中經過 MyIntentService.startActionBaz來啓動服務,你們能夠注意log日誌的輸出查看對應的方法是在哪一個線程中執行的(一般主[ui]線程id爲1,若是在對應的方法中輸出的線程id爲1代表是在ui線程中執行的,那麼千萬就不要在這樣的方法中執行費時操做了,以免ANR[程序未響應]的異常)。
輔助方法中是經過startService來啓動服務的,想必你們都知道在啓動成功後將調用Service的onCreate和onStartCommand方法,那 咱們就能夠從這兩個方法開始着手進入源碼分析。併發

  • IntentService.java
public void onCreate() {
          super.onCreate();
          HandlerThread thread = new   HandlerThread("IntentService[" + mName + "]");
        thread.start();
          mServiceLooper = thread.getLooper();
          mServiceHandler = new ServiceHandler(mServiceLooper);
         }

        public int onStartCommand(Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
        public void onDestroy() {
            mServiceLooper.quit();//退出Looper消息循環
        }

大概能夠得出結論:異步

  1. 啓動Service時在onCreate方法中啓動了一個HandlerThread的線程並生成了一個Looper用來分發消息之類的,同時建立了一個ServiceHandler的Handler用來處理消息
  2. onStartCommand中調用了onStart方法,那麼在onStart方法中作了些什麼操做呢?
  • IntentService.java
public void onStart(Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }

很明顯就是經過ServiceHandler來發送消息(發送到了HandlerThread的Looper消息隊列中),消息攜帶了intent對象(start Service啓動Service時的intent),那麼有發送消息就必定有處理消息的代碼。繼續查看ServiceHandler的代碼發現其是IntentService的內部類,定義以下:ide

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

能夠看出在handleMessage中調用了onHandleIntent方法並在方法結束後stopSelf中止了Service。繼續查看onHandleIntent方法的定義
IntentService.java
protected abstract void onHandleIntent(Intent intent);
OK,這個抽象方法必須在IntentService的子類中重寫,那麼在ServiceHandler的handleMessage中調用的將是子類中重寫的onHandleIntent方法,因此在咱們的MyIntentService類中的onHandleIntent方法被調用(經過Java的多態機制實現了一個「模版方法」的設計模式)oop

到此源碼基本分析結束,能夠得出結論以下:源碼分析

  1. 啓動IntentService類型的Service後,系統經過ServiceHandler將攜帶的Intent消息放入由HandlerThread線程生成的Looper的消息隊列中,Looper依次處理隊列中的消息並經過dispatchMessage將消息交給ServiceHandler的Handler來具體執行(其實就是Handler的用法,和咱們在Activity中建立Handler並在handleMessage中更新ui的用法同樣,只不過這裏的handleMessage是在HandlerThread這樣的後臺線程而不是ui線程中執行的)
  2. 調用子類的onHandleIntent方法(用來執行費時操做),結束後關閉Service
    總之,這種機制一般用於但願按順序執行(串行)而非併發(並行)執行的費時操做,其中每一個任務執行完畢的時間是未知的的應用場景。若是但願在任務結束後通知前臺能夠經過sendBroadCast的方式發送廣播。

HandlerThread類的關鍵代碼(Service的onCreate方法中建立並start啓動了線程):學習

/**
    典型的建立Looper步驟:
    //生成Looper實例
    Looper.prepare();
    Looper.myLooper();
    //啓動Looper循環
    Looper.loop();
    */
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

這裏比較難理解的是線程的安全同步代碼,在onCreate方法中調用順序以下:ui

HandlerThread thread = new HandlerThread();
    thread.start();
    thread.getLooper();

想必你們都知道線程的基本知識,這裏就很少介紹了。在線程調用start後並不必定run方法馬上獲得執行(異步調用的),因此在執行thread.getLooper()時這個時候run尚未執行。so,getLooper方法內部經過加鎖並有條件的wait()來一直等待mLooper不爲空。在run方法中能夠看到若是mLooper被初始化後會調用notifyAll()來通知全部正處於wait的線程繼續執行,這時getLooper方法中的return mLooper;將獲得執行。

相關文章
相關標籤/搜索