一篇文章了解IntentService的工作原理

IntentService

簡(jiǎn)介:繼承自Service,可以做耗時(shí)任務(wù)的Service。

  1. 使用
    • 創(chuàng)建Service繼承IntentService

      創(chuàng)建 MyIntentService 繼承IntentService ,實(shí)現(xiàn) onHandleIntent方法。

      public class MyIntentService extends IntentService {
      
          private String TAG = getClass().getSimpleName();
      
      
          public MyIntentService() {
              super("MyIntentService");
          }
      
          @Override
          protected void onHandleIntent(Intent intent) {
              Log.d(TAG, "onHandleIntent BEGIN");
              try {
                  Thread.sleep(11000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
             String value= intent.getStringExtra("key");
              Log.d(TAG, "onHandleIntent " +value);
              Log.d(TAG, "onHandleIntent END");
          }
      
          @Override
          public void onCreate() {
              super.onCreate();
              Log.d(TAG, "onCreate");
          }
      
          @Override
          public void onStart(Intent intent, int startId) {
              super.onStart(intent, startId);
              Log.d(TAG, "onStart");
          }
      
          @Override
          public int onStartCommand(Intent intent, int flags, int startId) {
              Log.d(TAG, "onStartCommand");
              return super.onStartCommand(intent, flags, startId);
          }
      
          @Override
          public void onDestroy() {
              super.onDestroy();
              Log.d(TAG, "onDestroy");
          }
      
      
    • 開啟Service

      public class MainActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              Intent intent=new Intent(this,MyIntentService.class);
              intent.putExtra("key","hello");
              startService(intent);
          }
      }
      
  2. 源碼解析

? 首先看一個(gè)問題,在 onHandleIntent中我先 sleep 了11秒,然后處理intent,為什么沒有Anr呢。

? 第二問題,為什么會(huì)出現(xiàn)IntentService呢,IntentService與Service的區(qū)別。接下來通過源碼去看上面兩個(gè)問 題。當(dāng)開啟Service時(shí)會(huì)先調(diào)用 onCreate 方法,接下來就先查看onCreate的源碼 看看究竟做了什么

 @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

? 在onCreate中當(dāng)創(chuàng)建了HandlerThread,HandlerThread繼承自Thread,然后開啟了線程,接下來調(diào)用了HandlerThread的getLooper方法,獲取Looper,然后創(chuàng)建ServiceHandler,ServiceHandler是一個(gè)Handler類。

到這里,看到Handler,能想到IntentService內(nèi)部封裝了Handler的消息機(jī)制。接下來分析上述代碼。

開啟線程會(huì)調(diào)用HandlerThread的run方法。

  @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

在方法中,首先調(diào)用Looper.prepare()方法,該方法創(chuàng)建Looper類和消息隊(duì)列,然后獲取鎖,獲取Looper對(duì)象,并調(diào)用notifyAll(),喚醒在等待池中的等待的線程。接著調(diào)用Looper.loop()方法,開啟消息隊(duì)列循環(huán)處理消息。

接下來分析thread.getLooper()這句代碼。

   public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

在該方法內(nèi),獲取鎖,并添加條件Looper是為null的話,調(diào)用wait,進(jìn)入等待。剛在上述的線程的run方法中,獲取到looper對(duì)象時(shí),調(diào)用了notifyAll方法。總結(jié)上述代碼。就是創(chuàng)建了Looper對(duì)象和消息隊(duì)列,創(chuàng)建Handler,接下來要找到是如何調(diào)用sendMessage方法來添加消息。

接下來分析onStartCommand方法。

 @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

在該方法內(nèi)調(diào)用了onStart方法。

@Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

在該方法內(nèi)終于找到了添加消息的方法。在這個(gè)方法內(nèi)發(fā)送消息,然后然后在消息隊(duì)列中一直在循環(huán)消息,若有消息便會(huì)處理,并最終調(diào)用Handler的handlerMessage方法。

   public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

剛方法內(nèi)調(diào)用了onHandleIntent這個(gè)抽象方法。并最終由我們自己的書寫的Service實(shí)現(xiàn)。

然后回頭看我們開頭的第一個(gè)問題,問什么沒有anr呢,因?yàn)槲覀兊膌ooper.loop()方法是在HandlerThread中的run方法調(diào)用的,looper.loop()最終會(huì)調(diào)用handler的handlerMessage方法,所以handlerMessage是在HandlerThread這個(gè)工作線程中調(diào)用的,不是在主線程中調(diào)用。所以不會(huì)出現(xiàn)anr。

IntentService與service的區(qū)別:Service是運(yùn)行在主線程中的,所以Service的方法不能做耗時(shí)任務(wù),不然會(huì)出現(xiàn)anr,IntentService是專門處理在Service中做耗時(shí)任務(wù)的類。因此,若以后需要早Service中處理耗時(shí)任務(wù)不必在Service中再開線程處理,可以直接用IntentService處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言:本文所寫的是博主的個(gè)人見解,如有錯(cuò)誤或者不恰當(dāng)之處,歡迎私信博主,加以改正!原文鏈接,demo鏈接 Serv...
    PassersHowe閱讀 1,516評(píng)論 0 5
  • Android四大組件之ActivityAndroid四大組件之ServiceAndroid四大組件之Broadc...
    MonkeyLqj閱讀 2,667評(píng)論 0 4
  • 參考: 服務(wù)|Android Developers 一. 什么是服務(wù) 服務(wù)是一個(gè)可以在后臺(tái)執(zhí)行長時(shí)間運(yùn)行操作而不提...
    NickelFox閱讀 601評(píng)論 0 3
  • 本篇文章是繼續(xù)上篇android圖片壓縮上傳系列-基礎(chǔ)篇文章的續(xù)篇。主要目的是:通過Service來執(zhí)行圖片壓縮任...
    laogui閱讀 4,508評(píng)論 5 62
  • 你在那里 我在這里 中間隔著長長的夜 我在孤獨(dú)寂寞中爬行 看不清前進(jìn)的路 你那愛的召喚忽隱忽現(xiàn) 月光星光螢蟲光……...
    開心點(diǎn)金石閱讀 114評(píng)論 0 3

友情鏈接更多精彩內(nèi)容