《Android開發藝術探索》 IntentService工作原理

HandlerThread


HandlerThread繼承了Thread,它是一種可以使用Handler的Thread,它的實現也很簡單,就是在run方法中通過Looper.prepare()來創建消息隊列,並通過Looper.loop()來開啓消息循環,這樣在實際的使用中就允許在HandlerThread中創建Handler了。HandlerThread的run方法如下所示。
  1. @Override
  2. public void run() {
  3. mTid = Process.myTid();
  4. // 創建當前線程的Looper對象
  5. Looper.prepare();
  6. synchronized (this) {
  7. // 獲取當前Looper對象
  8. mLooper = Looper.myLooper();
  9. // 喚醒wait等待
  10. notifyAll();
  11. }
  12. // 設置當前線程的優先級
  13. Process.setThreadPriority(mPriority);
  14. onLooperPrepared();
  15. // 循環取消息,沒有消息則等待
  16. Looper.loop();
  17. mTid = -1;
  18. }
從HandlerThread的實現來看,它和普通的Thread有顯著的不同之處。普通Thread主要用於在run方法中執行一個耗時任務,而HandlerThread在內部創建了消息隊列,外界需要通過Handler的消息方式來通知HandlerThread執行一個具體的任務。HandlerThread是一個很有用的類,它在Android中的一個具體的使用場景是IntentService。由於HandlerThread的run方法是一個無限循環,因此當明確不需要再使用HandlerThread時,可以通過它的quit或者quitSafely方法來終止線程的執行,這是一個良好的編程習慣。

HandlerThread 獲取Looper方法


  1. public Looper getLooper() {
  2. // 判斷是否啓動了線程
  3. if (!isAlive()) {
  4. return null;
  5. }
  6. // If the thread has been started, wait until the looper has been created.
  7. synchronized (this) {
  8. while (isAlive() && mLooper == null) {
  9. try {
  10. wait();
  11. } catch (InterruptedException e) {
  12. }
  13. }
  14. }
  15. return mLooper;
  16. }

HandlerThread 終止線程方法


  1. public boolean quit() {
  2. Looper looper = getLooper();
  3. if (looper != null) {
  4. // 直接終止
  5. looper.quit();
  6. return true;
  7. }
  8. return false;
  9. }
  1. public boolean quitSafely() {
  2. Looper looper = getLooper();
  3. if (looper != null) {
  4. // 等待消息全部處理完後終止
  5. looper.quitSafely();
  6. return true;
  7. }
  8. return false;
  9. }

IntentService工作原理


IntentService是一種特殊的Service,它繼承了Service並且它是一個抽象類,因此必須創建它的子類才能使用IntentService。IntentService可用於執行後臺耗時的任務,當任務執行後它會自動停止,同時由於IntentService是服務的原因,這導致它的優先級比單純的線程要高很多,所以IntentService比較適合執行一些高優先級的後臺任務,因爲它優先級高不容易被殺死。在實現上,IntentService封裝了HandlerThread和Handler,這一點可以從它的onCreate方法中看出來,如下所示。
  1. public void onCreate() {
  2. // TODO: It would be nice to have an option to hold a partial wakelock
  3. // during processing, and to have a static startService(Context, Intent)
  4. // method that would launch the service & hand off a wakelock.
  5. super.onCreate();
  6. // 創建HandlerThread線程對象,並設置線程名字
  7. HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
  8. // 開啓線程,執行HandlerThread的run方法
  9. thread.start();
  10. // 獲取HandlerThread線程中的Looper對象
  11. mServiceLooper = thread.getLooper();
  12. // 創建Handler,並設置爲HandlerThread的Looper對象
  13. mServiceHandler = new ServiceHandler(mServiceLooper);
  14. }
當IntentService被第一次啓動時,它的onCreate方法會被調用,onCreate方法會創建一個HandlerThread,然後使用它的Looper來構造一個Handler對象mServiceHandler,這樣通過mServiceHandler發送的消息最終都會在HandlerThread中執行,從這個角度來看,IntentService也可以用於執行後臺任務。每次啓動IntentService,它的onStartCommand方法就會調用一次,IntentService在onStartCommand中處理每個後臺任務的Intent。下面看一下onStartCommand方法是如何處理外界的Intent的,onStartCommand調用了onStart,onStart方法的實現如下所示。
  1. public void onStart(Intent intent, int startId) {
  2. Message msg = mServiceHandler.obtainMessage();
  3. msg.arg1 = startId;
  4. msg.obj = intent;
  5. mServiceHandler.sendMessage(msg);
  6. }
可以看出,IntentService僅僅是通過mServiceHandler發送了一個消息,這個消息會在HandlerThread中被處理。mServiceHandler收到消息後,會將Intent對象傳遞給onHandleIntent方法去處理。注意這個Intent對象的內容和外界的startService(intent)中的intent的內容是完全一致的,通過這個Intent對象即可解析出外界啓動IntentService時所傳遞的參數,通過這些參數就可以區分具體的後臺任務,這樣在onHandleIntent方法中就可以對不同的後臺任務做處理了。當onHandleIntent方法執行結束後,IntentService會通過stopSelf(int startId)方法來嘗試停止服務。這裏之所以採用stopSelf(int startId)而不是stopSelf()來停止服務,那是因爲stopSelf()會立刻停止服務,而這個時候可能還有其他消息未處理,stopSelf(int startId)則會等待所有的消息都處理完畢後才終止服務。一般來說,stopSelf(int startId)在嘗試停止服務之前會判斷最近啓動服務的次數是否和startId相等,如果相等就立刻停止服務,不相等則不停止服務。
ServiceHandler的實現如下所示。
  1. private final class ServiceHandler extends Handler {
  2. public ServiceHandler(Looper looper) {
  3. super(looper);
  4. }
  5. @Override
  6. public void handleMessage(Message msg) {
  7. // 讓子類去處理業務
  8. onHandleIntent((Intent)msg.obj);
  9. // 停止服務
  10. stopSelf(msg.arg1);
  11. }
  12. }
  1. protected abstract void onHandleIntent(Intent intent);
  1. public void onDestroy() {
  2. // 退出Looper循環
  3. mServiceLooper.quit();
  4. }
IntentService的onHandleIntent方法是一個抽象方法,它需要我們在子類中實現,它的作用是從Intent參數中區分具體的任務並執行這些任務。如果目前只存在一個後臺任務,那麼onHandleIntent方法執行完成這個任務後,stopSelf(int startId)就會直接停止服務;如果目前存在多個後臺任務,那麼當onHandleIntent方法執行完最後一個任務是,stopSelf(int startId)纔會直接停止服務。另外,由於每執行一個後臺任務就必須啓動一次IntentService,而IntentService內部則通過消息的方式向HandlerThread請求執行任務,Handler中的Looper是順序處理消息的,這就意味着IntentService也是順序執行後臺任務的,當有多個後臺任務同時存在時,這些後臺任務會按照外界發起的順序排隊執行。












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