無論學什麼知識點最好從其基本用法開始,而後在深刻到源碼層學習會比較容易理解源碼帶給咱們的思想。因此我們先來看看IntentService的基本用法。java
其實很簡單,遵照必定的套路就能夠設計模式
好比:安全
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方法,那 咱們就能夠從這兩個方法開始着手進入源碼分析。併發
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消息循環 }
大概能夠得出結論:異步
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
到此源碼基本分析結束,能夠得出結論以下:源碼分析
但願按順序執行(串行)而非併發(並行)執行的費時操做,其中每一個任務執行完畢的時間是未知的
的應用場景。若是但願在任務結束後通知前臺能夠經過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;將獲得執行。