HandlerThread完全解析

為什么需要HandlerThread?

HandlerThread本質(zhì)上就是一個(gè)普通Thread,只不過(guò)內(nèi)部建立了Looper,handlerthread實(shí)質(zhì)上建立了一個(gè)模型,簡(jiǎn)化了像下面這種子線(xiàn)程與子線(xiàn)程之間的通信。
子線(xiàn)程和子線(xiàn)程之間的通信:

public class MainActivity extends AppCompatActivity {
    private Handler handler1;
    private Handler handler2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new MyThread1().start();
        new MyThread2().start();
    }
    class MyThread1 extends Thread {
        @Override
        public void run() {
            super.run();

            Looper.prepare();

            handler1 = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);
                }
            };
            try {
                sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler2.sendEmptyMessage(2);
            Looper.loop();
        }
    }

    class MyThread2 extends Thread {
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler2 = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);
                }
            };
            try {
                sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler1.sendEmptyMessage(5);
            Looper.loop();
        }
    }
}
  1. 調(diào)用Looper類(lèi)的 prepare() 方法可以為當(dāng)前線(xiàn)程創(chuàng)建一個(gè)消息循環(huán),調(diào)用loop() 方法使之處理信息,直到循環(huán)結(jié)束。
  1. Handler有幾個(gè)構(gòu)造重載,如果構(gòu)造時(shí)不提供Looper類(lèi)對(duì)象參數(shù),會(huì)獲取當(dāng)前線(xiàn)程的Looper對(duì)象,即將當(dāng)前線(xiàn)程的消息循環(huán)作為Handler關(guān)聯(lián)的消息循環(huán)。
  2. 消息處理機(jī)制中,消息存放在一個(gè)消息隊(duì)列中,而線(xiàn)程圍繞這個(gè)隊(duì)列進(jìn)入一個(gè)無(wú)限循環(huán),直到程序退出。如果隊(duì)列中有消息,線(xiàn)程就會(huì)把消息取出來(lái),并分發(fā)給相應(yīng)的Handler進(jìn)行處理;如果隊(duì)列中沒(méi)有消息,線(xiàn)程就會(huì)進(jìn)入空閑等待狀態(tài),等待下一個(gè)消息的到來(lái)。

HandlerThread的用法

public class MainActivity extends AppCompatActivity {

    private HandlerThread myHandlerThread ;
    private Handler handler ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //創(chuàng)建一個(gè)線(xiàn)程,線(xiàn)程名字:handler-thread
        myHandlerThread = new HandlerThread( "handler-thread") ;
        //開(kāi)啟一個(gè)線(xiàn)程
        myHandlerThread.start();
        //在這個(gè)線(xiàn)程中創(chuàng)建一個(gè)handler對(duì)象
        handler = new Handler( myHandlerThread.getLooper() ){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //這個(gè)方法是運(yùn)行在 handler-thread 線(xiàn)程中的 ,可以執(zhí)行耗時(shí)操作
                Log.d( "handler " , "消息: " + msg.what + "  線(xiàn)程: " + Thread.currentThread().getName()  ) ;

            }
        };

        //在主線(xiàn)程給handler發(fā)送消息
        handler.sendEmptyMessage( 1 ) ;

        new Thread(new Runnable() {
            @Override
            public void run() {
             //在子線(xiàn)程給handler發(fā)送數(shù)據(jù)
             handler.sendEmptyMessage( 2 ) ;
            }
        }).start() ;

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        //釋放資源
        myHandlerThread.quit() ;
    }
}

運(yùn)行效果:

/com.app D/handler: 消息: 1  線(xiàn)程: handler-thread
/com.app D/handler: 消息: 2  線(xiàn)程: handler-thread

HandlerThread退出循環(huán)的方法
Looper是通過(guò)調(diào)用loop方法驅(qū)動(dòng)著消息循環(huán)的進(jìn)行: 從MessageQueue中阻塞式地取出一個(gè)消息,然后讓Handler處理該消息,周而復(fù)始,loop方法是個(gè)死循環(huán)方法。那如何終止消息循環(huán)呢?

handlerThread.quit()
或
handlerThread.quitSafely()
  • 相同點(diǎn):
    將不在接受新的事件加入消息隊(duì)列。無(wú)論是調(diào)用了quit方法還是quitSafely方法只會(huì),Looper就不再接收新的消息。即在調(diào)用了Looper的quit或quitSafely方法之后,消息循環(huán)就終結(jié)了,這時(shí)候再通過(guò)Handler調(diào)用sendMessage或post等方法發(fā)送消息時(shí)均返回false,表示消息沒(méi)有成功放入消息隊(duì)列MessageQueue中,因?yàn)橄㈥?duì)列已經(jīng)退出了。
  • 不同點(diǎn)
  • 當(dāng)我們調(diào)用Looper的quit方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無(wú)論是延遲消息(延遲消息是指通過(guò)sendMessageDelayed或通過(guò)postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息。
  • 當(dāng)我們調(diào)用Looper的quitSafely方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過(guò)名字就可以看出,該方法只會(huì)清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會(huì)派發(fā)所有的非延遲消息。

需要注意的是Looper的quit方法從API Level 1就存在了,但是Looper的quitSafely方法從API Level 18才添加進(jìn)來(lái)。

HandlerThread要點(diǎn)

  1. HandlerThread將loop轉(zhuǎn)到子線(xiàn)程中處理,說(shuō)白了就是將分擔(dān)MainLooper的工作量,降低了主線(xiàn)程的壓力,使主界面更流暢,不阻塞UI線(xiàn)程。
  2. 處理任務(wù)是串行執(zhí)行,按消息發(fā)送順序進(jìn)行處理。HandlerThread本質(zhì)是一個(gè)線(xiàn)程,在線(xiàn)程內(nèi)部,代碼是串行處理的。
  3. 對(duì)于網(wǎng)絡(luò)IO操作,HandlerThread并不適合,因?yàn)樗挥幸粋€(gè)線(xiàn)程,每一個(gè)任務(wù)都將以隊(duì)列的方式逐個(gè)被執(zhí)行到,一旦隊(duì)列中有某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),那么就會(huì)導(dǎo)致后續(xù)的任務(wù)都會(huì)被延遲處理。
  4. HandlerThread在不需要使用的時(shí)候需要手動(dòng)的回收掉;

HandlerThread源碼解析

我們通過(guò)

//創(chuàng)建一個(gè)線(xiàn)程,線(xiàn)程名字:handler-thread
        myHandlerThread = new HandlerThread( "handler-thread") ;
        //開(kāi)啟一個(gè)線(xiàn)程
        myHandlerThread.start();

創(chuàng)建和啟動(dòng)HandlerThread.
對(duì)應(yīng)源碼為:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    protected void onLooperPrepared() {
    }

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

其實(shí)我們就是初始化和啟動(dòng)了一個(gè)線(xiàn)程;然后我們看run()方法,可以看到該方法中調(diào)用了Looper.prepare(),Loop.loop();prepare()中創(chuàng)建了一個(gè)Looper對(duì)象,并且把該對(duì)象放到了該線(xiàn)程范圍內(nèi)的變量中(sThreadLocal),在Looper對(duì)象的構(gòu)造過(guò)程中,初始化了一個(gè)MessageQueue,作為該Looper對(duì)象成員變量。
loop()就開(kāi)啟了,不斷的循環(huán)從MessageQueue中取消息處理了,當(dāng)沒(méi)有消息的時(shí)候會(huì)阻塞,有消息的到來(lái)的時(shí)候會(huì)喚醒。
接下來(lái),我們創(chuàng)建了一個(gè)handler

 handler = new Handler( myHandlerThread.getLooper() )

對(duì)應(yīng)源碼為:

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

myHandlerThread.getLooper()返回的就是我們?cè)趓un方法中創(chuàng)建的mLooper。
如果你夠細(xì)心你會(huì)發(fā)現(xiàn),run方法里面當(dāng)mLooper創(chuàng)建完成后有個(gè)notifyAll(),getLooper()中有個(gè)wait(),這是為什么呢?因?yàn)榈膍Looper在一個(gè)線(xiàn)程中執(zhí)行,而我們的handler是在UI線(xiàn)程初始化的,也就是說(shuō),我們必須等到mLooper創(chuàng)建完成,才能正確的返回getLooper()。wait(),notify()就是為了解決這兩個(gè)線(xiàn)程的同步問(wèn)題。

參考

Android Handler、Loop 的簡(jiǎn)單使用

最后編輯于
?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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