Android中的線(xiàn)程形態(tài)(二)(HandlerThread/IntentService)

本篇提綱(二).png

一.HandlerThread的使用與原理解析

??HandlerThread繼承于Thread,所以它本質(zhì)就是個(gè)Thread。與普通Thread的差別就在于,它不僅建立了一個(gè)線(xiàn)程,并且創(chuàng)立了消息隊(duì)列,有自己的looper,可以讓我們?cè)谧约旱木€(xiàn)程中分發(fā)和處理消息,并對(duì)外提供自己這個(gè)Looper對(duì)象的get方法。
??HandlerThread自帶Looper使他可以通過(guò)消息隊(duì)列,來(lái)重復(fù)使用當(dāng)前線(xiàn)程,節(jié)省系統(tǒng)資源開(kāi)銷(xiāo)。這是它的優(yōu)點(diǎn)也是缺點(diǎn),每一個(gè)任務(wù)都將以隊(duì)列的方式逐個(gè)被執(zhí)行到,一旦隊(duì)列中有某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),那么就會(huì)導(dǎo)致后續(xù)的任務(wù)都會(huì)被延遲處理。

1.HandlerThread使用步驟

第一步:創(chuàng)建HandlerThread實(shí)例對(duì)象

HandlerThread handlerThread = new HandlerThread("myThread");

第二步:啟動(dòng)HandlerThread線(xiàn)程

handlerThread.start();

第三步:構(gòu)建循環(huán)消息處理機(jī)制

 private Handler.Callback mSubCallback = new Handler.Callback() {
        //該接口的實(shí)現(xiàn)就是處理異步耗時(shí)任務(wù)的,因此該方法執(zhí)行在子線(xiàn)程中
        @Override
        public boolean handleMessage(Message msg) {
                //doSomething  處理異步耗時(shí)任務(wù)的
                mUIHandler.sendMessage(msg1);   //向UI線(xiàn)程發(fā)送消息,用于更新UI等操作
        }
    };

第四步:構(gòu)建子線(xiàn)程中的Handler:

//由于這里已經(jīng)獲取了workHandle.getLooper(),因此這個(gè)Handler是在HandlerThread線(xiàn)程也就是子線(xiàn)程中
childHandler = new Handler(handlerThread.getLooper(), mSubCallback);
button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        //發(fā)送異步耗時(shí)任務(wù)到HandlerThread中,也就是上面的mSubCallback中
        childHandler.sendMessage(msg);
    }
});

第五步:構(gòu)建UI線(xiàn)程Handler處理消息(如果需要更新UI的話(huà)有這一步)

    private Handler mUIHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //在UI線(xiàn)程中做的事情,比如設(shè)置圖片什么的
        }
    };

2.HandlerThread的實(shí)現(xiàn)原理

??HandlerThread的實(shí)現(xiàn)原理比較簡(jiǎn)單,源碼也比較少(只有150行代碼),首先它是繼承自Thread類(lèi)的:

public class HandlerThread extends Thread {

因此它完全可以當(dāng)一個(gè)線(xiàn)程來(lái)使用,就像上面我們說(shuō)的:new HandlerTread().start()這樣,但是!!!——我們之前在Android中的消息機(jī)制——Looper、Handler、MessageQueue與Message這篇文章中說(shuō)過(guò),在子線(xiàn)程中創(chuàng)建一個(gè)Handler,需要手動(dòng)創(chuàng)建Looper,即先Looper.parpare(),完了再Looper.loop()
這樣,我們來(lái)看看HandlerThread中的run方法:

    @Override
    public void run() {
        mTid = Process.myTid();  //獲得當(dāng)前線(xiàn)程的id
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            //發(fā)出通知,當(dāng)前線(xiàn)程已經(jīng)創(chuàng)建mLooper對(duì)象成功,這里主要是通知getLooper方法中的wait
            notifyAll();
        }
        //設(shè)置當(dāng)前線(xiàn)程的優(yōu)先級(jí)
        Process.setThreadPriority(mPriority);
        //該方法實(shí)現(xiàn)體是空的,子類(lèi)可以實(shí)現(xiàn)該方法,作用就是在線(xiàn)程循環(huán)之前做一些準(zhǔn)備工作,當(dāng)然子類(lèi)也可以不實(shí)現(xiàn)。
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

可以看到,這個(gè)run方法里邊寫(xiě)死了,先Looper.prepare()然后Looper.loop(),也即是說(shuō),我們的HandlerThread這個(gè)特殊的“線(xiàn)程”是再帶Looper的,因此——我們不能再主線(xiàn)程使用它,畢竟主線(xiàn)程是自帶MainLooper的,一個(gè)線(xiàn)程只能有一個(gè)Looper,否則就會(huì)拋出異常。
??這里我們說(shuō)一下,為什么要看這個(gè)run()方法,之前我們?cè)?a href="http://www.lxweimin.com/p/72194931f805" target="_blank">Android中的線(xiàn)程形態(tài)(一)(進(jìn)程/線(xiàn)程/線(xiàn)程池)中有講過(guò),Thread工作的時(shí)候,不論哪種實(shí)現(xiàn)方法,我們都必須重寫(xiě)這個(gè)類(lèi)的run()方法,在其中寫(xiě)我們自己要做的事情。可以看到,HandlerThread類(lèi)的run()方法已經(jīng)給我們寫(xiě)死了,這就注定我們只能將它用在子線(xiàn)程中。

??我們?cè)賮?lái)看看HandelerThread類(lèi)的額另一個(gè)重要的方法——getLooper():

    //該方法主要作用是獲得當(dāng)前HandlerThread線(xiàn)程中的mLooper對(duì)象
    public Looper getLooper() {
        if (!isAlive()) {   //如果線(xiàn)程不是活動(dòng)的,則直接返回null
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        //如果線(xiàn)程已經(jīng)啟動(dòng),但是Looper還未創(chuàng)建的話(huà),就等待,直到Looper創(chuàng)建成功
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    //這里會(huì)調(diào)用wait方法去等待,當(dāng)run方法中的notifyAll方法調(diào)用之后
                    //通知當(dāng)前線(xiàn)程的wait方法等待結(jié)束,跳出循環(huán),獲得mLooper對(duì)象的值。
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

OK,看到這里,結(jié)合上面的HandelrThread使用步驟,我們需要總結(jié)一下:

  • HandelrThread是一個(gè)自帶Looper的線(xiàn)程,因此只能作為子線(xiàn)程使用
  • HandlerThread必須配合Handler使用,HandlerThread線(xiàn)程中做具體事情,必須要在Handler的callback接口中進(jìn)行,他自己的run方法被寫(xiě)死了。
  • 子線(xiàn)程中的Handler與HandlerThread的聯(lián)系是通過(guò)childHandler = new Handler(handlerThread.getLooper(), mSubCallback);這句來(lái)進(jìn)行的,也就是你說(shuō),childHandler獲得HandlerThread線(xiàn)程的Looper,這樣,他們兩個(gè)就在同一陣營(yíng)了。這也就是在創(chuàng)建Handler作為HandlerThread線(xiàn)程消息執(zhí)行者,必須在調(diào)用start()方法之后的原因——HandlerThread.start()之后,run()方法才能跑起來(lái),Looper才能得以創(chuàng)建,handlerThread.getLooper()才不會(huì)出錯(cuò)。

二.IntentService的使用與實(shí)現(xiàn)原理

??HandlerThread在Android中的一個(gè)具體的應(yīng)用就是IntentService。IntentService是繼承于Service并處理異步請(qǐng)求的一個(gè)類(lèi)。注意這句話(huà)——“繼承于Service”“處理異步請(qǐng)求”“繼承于Service”表示他是一個(gè)服務(wù),我們知道Service是存在于主線(xiàn)程的,它之中不能存在耗時(shí)操作,否則的話(huà)回應(yīng)起ANR,因此便有了IntentService——這個(gè)封裝了HandlerThread和Handler的特殊Service。

1.IntentService的使用

第一步:創(chuàng)建一個(gè)繼承IntentService類(lèi)的子類(lèi)
首先,通過(guò)源碼我們知道,IntentService是一個(gè)繼承自Service類(lèi)的抽象類(lèi),因此我們必須創(chuàng)建一個(gè)繼承它的子類(lèi)才能實(shí)現(xiàn)相關(guān)功能:

public class MyIntentService extends IntentService {

    public ServiceUpdate() {
         // 注意構(gòu)造函數(shù)參數(shù)為空,這個(gè)myIntentService字符串就是IntentService中工作線(xiàn)程的名字
         super("myIntentService");
    }

    //打印生命周期
    @Override
    public void onCreate() {
        Log.i("myIntentService", "onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("myIntentService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    
    @Override
      public void onStart(Intent intent, int startId) {
          Log.i("myIntentService", "onStart");
          super.onStart(intent, startId);
      }
    
     @Override
      public IBinder onBind(Intent intent) {
        Log.i("myIntentService", "onBind");
        return super.onBind(intent);
      }
      
    //重寫(xiě)onHandleIntent方法,在該方法中進(jìn)行我們的各種事務(wù)處理
    @Override
    protected void onHandleIntent(Intent intent) {
         //一般Intent是從Activity發(fā)過(guò)來(lái)的,攜帶識(shí)別參數(shù),根據(jù)參數(shù)不同執(zhí)行不同的任務(wù)
        String taskName = intent.getExtras().getString("taskName");
        switch (taskName) {
        case "task1":
            Log.i("myIntentService", "task1");
            break;
        case "task2":
            Log.i("myIntentService", "task2");
            break;
        default:
            break;
        }
    }

    @Override
    public void onDestroy() {
        Log.i("myIntentService", "onDestroy");
        super.onDestroy();
    }
}

第二步:在Activity中開(kāi)啟服務(wù):

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        ......

        //同一服務(wù)只會(huì)開(kāi)啟一個(gè)工作線(xiàn)程,在onHandleIntent函數(shù)里依次處理intent請(qǐng)求。
        Intent intent1 = new Intent(this,MyIntentService.class);
        Bundle bundle = new Bundle();
        bundle.putString("taskName", "task1");
        intent1.putExtras(bundle);
        startService(intent1);

        Intent intent2 = new Intent(this,MyIntentService.class);
        Bundle bundle2 = new Bundle();
        bundle2.putString("taskName", "task2");
        intent2.putExtras(bundle2);
        startService(intent2);
    }
}

第三步:在 Manifest 中注冊(cè)服務(wù)

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

上述過(guò)程中我們啟動(dòng)了兩個(gè)IntentService服務(wù),打印出來(lái)生命周期為:onCreate -> onStartCommand -> onStart -> onStartCommand -> onStart -> task1 -> task2 -> onDestroy,OnBinder沒(méi)有執(zhí)行。
??從結(jié)果可以看到,onCreate 方法只執(zhí)行了一次,而 onStartCommand 和 onStart 方法執(zhí)行了兩次,開(kāi)啟了兩個(gè) 工作線(xiàn)程(Work Thread),這就證實(shí)了之前所說(shuō)的,啟動(dòng)多次,但I(xiàn)ntentService 的實(shí)例只有一個(gè),這跟傳統(tǒng)的Service 是一樣的。

2.IntentServic源碼分析

??IntentService繼承Service類(lèi)之后,整體的源碼也就165行,跟HandlerThread差不多,我們先來(lái)看看它的實(shí)例變量:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;     //服務(wù)所在線(xiàn)程的Looper
    private volatile ServiceHandler mServiceHandler;    //構(gòu)建一個(gè)服務(wù)中的Handler
    private String mName;       //服務(wù)所在線(xiàn)程的名字
    private boolean mRedelivery;
1).IntentService的構(gòu)造方法

上面加了注釋的三個(gè)變量較為重要,我們待會(huì)會(huì)一步步分析。接下來(lái)我們看看他的構(gòu)造方法:

    public IntentService(String name) {
        super();
        mName = name;
    }

可以看到,上線(xiàn)例子中我們得

    public ServiceUpdate() {
         super("myIntentService");
    }

其中“myIntentService”實(shí)際會(huì)上傳到父類(lèi)IntentService的構(gòu)造方法中,也就是IntentService所在線(xiàn)程的線(xiàn)程名字,IntentService構(gòu)造方法中的super();又會(huì)進(jìn)一步調(diào)用Service類(lèi)中的構(gòu)造函數(shù):

    public Service() {
        super(null);
    }

再網(wǎng)上,就到ContextWrapper類(lèi)里邊去了。如果我們看過(guò)Activity的源碼的話(huà)就會(huì)知道,Activity也是繼承自ContextWrapper類(lèi)的,而ContextWrapper類(lèi)繼承自Context!也就說(shuō),Service和Activity實(shí)際上都是一個(gè)Context!ContextWrapper有一個(gè)比較特殊的地方是,他的實(shí)例化的地方是在ActivityThread中由系統(tǒng)完成的,我們無(wú)權(quán)插手。因此,在StartService或者StartActivity的時(shí)候,系統(tǒng)就會(huì)自動(dòng)幫我們實(shí)例化這兩個(gè)組件。這樣,Service的構(gòu)造方法為空也就很好解釋了。

2).OnCreat()

??看上面的生命周期流程圖我們知道,IntentService第一步指定的onCreat方法:

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

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

首先,super.onCreate();,這個(gè)我們看到Service的onCreat()方法是空的,所以不管,接著看。HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");看到了吧,這里重量級(jí)人物——HandlerThread出場(chǎng)了,新建了一個(gè)HandlerThread實(shí)例,上面我們說(shuō)過(guò)HandlerThread()的構(gòu)造方法傳進(jìn)去的是HandlerThread所在線(xiàn)程的名字,然后thread.start();,嗯,非常符合我們上半片文章講的HandlerThread使用流程。
??mServiceLooper = thread.getLooper();這里通過(guò)mServiceLooper獲取到HandlerThread線(xiàn)程的Looper。然后mServiceHandler = new ServiceHandler(mServiceLooper);,我們接著看源碼:

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

可以看到,ServiceHandler是IntentService類(lèi)的一個(gè)內(nèi)部類(lèi),并且繼承自Handler,重寫(xiě)了handleMessage方法。很顯然,這個(gè)類(lèi)是用來(lái)處理startService(intent);傳遞來(lái)的消息的。這個(gè)消息處理的過(guò)程分為兩步,第一調(diào)用onHandleIntent((Intent)msg.obj);方法;第二步stopSelf(msg.arg1);消息處理完后自動(dòng)終止服務(wù)。所以我們接著而看onHandleIntent((Intent)msg.obj);:

    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);

呦呵?這是一個(gè)抽象方法,抽象類(lèi)中的抽象方法意味著我們需要在子類(lèi)中重寫(xiě)這個(gè)方法,也就是說(shuō),這個(gè)方法才是我們處理消息的地方。可以看到,這個(gè)方法上面加了注解,是位于工作線(xiàn)程(子線(xiàn)程)中的。

3).onStartCommand()/onStart()

??好了,OnCreat()方法終于執(zhí)行完了,onStartCommand()方法,它和onStart()方法實(shí)際上是連在一起的:

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

直接看onStart():

    @Override
    public void onStart(Intent intent, int startId) {
        //Service 啟動(dòng)后直接就向 mServiceHandler 發(fā)送消息,則馬上就會(huì)執(zhí)行 handleMessage方法
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

這個(gè)方法中,mServiceHandler這個(gè)Handler的子類(lèi),調(diào)用了obtainMessage()方法,該方法實(shí)際上上到Handler類(lèi)中調(diào)用的是:

    public final Message obtainMessage(){
        return Message.obtain(this);
    }

這個(gè)方法中,Message.obtain(this);這個(gè)方法我們復(fù)習(xí)一下,實(shí)際上就是Handler從消息池中取出一個(gè)消息,避免Message類(lèi)重復(fù)創(chuàng)建的一個(gè)方法。回到IntentSerice的onStart()方法中,Message msg = mServiceHandler.obtainMessage();,這句就是獲取一個(gè)Message對(duì)象,然后mServiceHandler.sendMessage(msg);通過(guò)Handler發(fā)送消息,添加到Looper中的MessageQuenue隊(duì)列中。

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

安全退出Looper()

3.IntentService中的一些坑

1).為什么不建議通過(guò) bindService() 啟動(dòng) IntentService?
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

??IntentService 源碼中的 onBind() 默認(rèn)返回 null;不適合 bindService() 啟動(dòng)服務(wù),如果你執(zhí)意要 bindService() 來(lái)啟動(dòng) IntentService,可能因?yàn)槟阆胪ㄟ^(guò) Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,這樣那么 onHandleIntent() 不會(huì)被回調(diào),相當(dāng)于在你使用 Service 而不是 IntentService。

2).為什么多次啟動(dòng) IntentService 會(huì)順序執(zhí)行事件,停止服務(wù)后,后續(xù)的事件得不到執(zhí)行?

??IntentService 中使用的 Handler、Looper、MessageQueue 機(jī)制把消息發(fā)送到線(xiàn)程中去執(zhí)行的,所以多次啟動(dòng) IntentService 不會(huì)重新創(chuàng)建新的服務(wù)和新的線(xiàn)程,只是把消息加入消息隊(duì)列中等待執(zhí)行,而如果服務(wù)停止,會(huì)清除消息隊(duì)列中的消息,后續(xù)的事件得不到執(zhí)行。

站在巨人的肩膀上摘蘋(píng)果:
IntentService 示例與詳解
Service 和 IntentService 的區(qū)別

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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