IntentService源碼分析

1.前言

想必大家應(yīng)該都使用過Service組件叁幢,為什么有service,還需要IntentService呢巍杈。它們有什么不同忧饭,帶著這些問題,下面我們分析下源碼筷畦。

2.IntentService源碼分析

public abstract class IntentService extends Service {
   private volatile Looper mServiceLooper;
   private volatile ServiceHandler mServiceHandler;
   private String mName;
   private boolean mRedelivery;

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

   /**
    * Creates an IntentService.  Invoked by your subclass's constructor.
    *
    * @param name Used to name the worker thread, important only for debugging.
    */
   public IntentService(String name) {
       super();
       mName = name;
   }

   /**
    * Sets intent redelivery preferences.  Usually called from the constructor
    * with your preferred semantics.
    *
    * <p>If enabled is true,
    * {@link #onStartCommand(Intent, int, int)} will return
    * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
    * {@link #onHandleIntent(Intent)} returns, the process will be restarted
    * and the intent redelivered.  If multiple Intents have been sent, only
    * the most recent one is guaranteed to be redelivered.
    *
    * <p>If enabled is false (the default),
    * {@link #onStartCommand(Intent, int, int)} will return
    * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
    * dies along with it.
    */
   public void setIntentRedelivery(boolean enabled) {
       mRedelivery = enabled;
   }

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

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

   /**
    * You should not override this method for your IntentService. Instead,
    * override {@link #onHandleIntent}, which the system calls when the IntentService
    * receives a start request.
    * @see android.app.Service#onStartCommand
    */
   @Override
   public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
       onStart(intent, startId);
       return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
   }

   @Override
   public void onDestroy() {
       mServiceLooper.quit();
   }

   /**
    * Unless you provide binding for your service, you don't need to implement this
    * method, because the default implementation returns null.
    * @see android.app.Service#onBind
    */
   @Override
   @Nullable
   public IBinder onBind(Intent intent) {
       return null;
   }

   /**
    * This method is invoked on the worker thread with a request to process.
    * Only one Intent is processed at a time, but the processing happens on a
    * worker thread that runs independently from other application logic.
    * So, if this code takes a long time, it will hold up other requests to
    * the same IntentService, but it will not hold up anything else.
    * When all requests have been handled, the IntentService stops itself,
    * so you should not call {@link #stopSelf}.
    *
    * @param intent The value passed to {@link
    *               android.content.Context#startService(Intent)}.
    *               This may be null if the service is being restarted after
    *               its process has gone away; see
    *               {@link android.app.Service#onStartCommand}
    *               for details.
    */
   @WorkerThread
   protected abstract void onHandleIntent(@Nullable Intent intent);
}

2.1 onCreate方法

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);
    }
public class HandlerThread extends Thread

可以看出在onCreate方法中HandlerThread變量词裤。可以看出HandlerThread其實(shí)就是一個(gè)線程鳖宾。在此啟動(dòng)一個(gè)線程吼砂。同時(shí)定義一個(gè)ServiceHandler的Handler,由于接收處理onStart發(fā)出的Message鼎文。接下來看看onStartCommand&onStart方法渔肩。

2.2 onStartCommand和onStart方法

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

在啟動(dòng)這個(gè)service的時(shí)候會(huì)調(diào)用onStartCommand方法,onStartCommand方法又會(huì)調(diào)用onStart方法拇惋,onStart干了什么事情呢周偎?其實(shí)就是發(fā)送Message給到ServiceHandler中。

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

然后處理onHandlerIntent()這個(gè)抽象方法撑帖。onHandlerIntent方法跑在onCreate方法開啟的線程中蓉坎。然后stopSelf()。

2.3 onDestroy方法

@Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

服務(wù)停止后會(huì)執(zhí)行onDestroy方法胡嘿,在onDestroy方法中會(huì)清除消息隊(duì)列Message蛉艾。所以IntentService多次啟動(dòng),如果服務(wù)停止了,會(huì)清除所有消息隊(duì)列的任務(wù),后面的任務(wù)不會(huì)執(zhí)行勿侯。因?yàn)槎寂茉谝粋€(gè)消息隊(duì)列中拓瞪,多次啟動(dòng)服務(wù)不會(huì)執(zhí)行onCreate方法,所以不會(huì)創(chuàng)建多個(gè)消息隊(duì)列罐监。

2.4 總結(jié)

由此可以看出Service和IntentService的區(qū)別
1.Service與IntentService本質(zhì)上是一個(gè)Service組件吴藻。
2.Service不能處理耗時(shí)過長的任務(wù),會(huì)引起ANR, 因?yàn)閟ervice運(yùn)行在UI線程上弓柱。
3.Service需要處理耗時(shí)任務(wù)必須自己開啟一個(gè)線程。
4.IntentService可以處理耗時(shí)任務(wù)侧但,并且不需要關(guān)心是否開啟工作線程矢空,繼承它就可以了,實(shí)現(xiàn)onHandleIntent抽象方法處理耗時(shí)操作就行了禀横。
5.使用IntentService不需要關(guān)心關(guān)閉Service屁药。在任務(wù)完成后會(huì)自動(dòng)stopSelf掉。
6.由源碼看出柏锄,IntentService不適合用bindService啟動(dòng)酿箭,因?yàn)閛nBind返回null微服,同時(shí)用bindService IntentService也不會(huì)回調(diào)onHandleIntent方法准验,也不會(huì)在service任務(wù)完成后停止。如果使用bindService啟動(dòng)IntentService惜颇,那僅僅是一個(gè)普通的Service抬闷。

3.如何使用

3.1繼承IntentService實(shí)現(xiàn)onHandleIntent方法

/**
 * Created by zw on 2019/7/7 11:31
 */
public class MyIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService(String name) {
       // 可以定義工作線程名稱
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
      // 處理耗時(shí)任務(wù)
    }
}

3.2 AndriodManifest.xml中注冊(cè)這個(gè)Service

<service android:name=".MyIntentService"/>

3.3 啟動(dòng)服務(wù)

startService(new Intent(this, MyIntentService.class));

That's All

IntentService源碼onCreate方法里出現(xiàn)的Looper妇蛀,Message, Handler另外MessageQueue將在接下來分析它們。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笤成,一起剝皮案震驚了整個(gè)濱河市评架,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炕泳,老刑警劉巖纵诞,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異培遵,居然都是意外死亡浙芙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門荤懂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茁裙,“玉大人,你說我怎么就攤上這事节仿∥钭叮” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矾瘾。 經(jīng)常有香客問我女轿,道長,這世上最難降的妖魔是什么壕翩? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任蛉迹,我火速辦了婚禮,結(jié)果婚禮上放妈,老公的妹妹穿的比我還像新娘北救。我一直安慰自己,他們只是感情好芜抒,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布珍策。 她就那樣靜靜地躺著,像睡著了一般宅倒。 火紅的嫁衣襯著肌膚如雪攘宙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天拐迁,我揣著相機(jī)與錄音蹭劈,去河邊找鬼。 笑死线召,一個(gè)胖子當(dāng)著我的面吹牛铺韧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灶搜,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼祟蚀,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了割卖?” 一聲冷哼從身側(cè)響起前酿,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鹏溯,沒想到半個(gè)月后罢维,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丙挽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年肺孵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颜阐。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡平窘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凳怨,到底是詐尸還是另有隱情瑰艘,我是刑警寧澤是鬼,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站紫新,受9級(jí)特大地震影響均蜜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芒率,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一囤耳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偶芍,春花似錦充择、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至萄窜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撒桨,已是汗流浹背查刻。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凤类,地道東北人穗泵。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像谜疤,于是被迫代替她去往敵國和親佃延。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容