第六章 Handler專題

一、什么是Handler

由于Android的只允許在UI線程(主線程)中修改UI組件,為了解決其他線程無法改變組件屬性值而使用Handler類處理
作用:

  • 在新啟動(dòng)的線程中發(fā)送消息
  • 在主線程中獲取處理消息

二、Handler的使用

1.post(Runnable)

post方法用于handleMessage()的作用一樣處理數(shù)據(jù)更新UI,源碼如下,也是調(diào)用sendMessageDelayed方法,省略了很多創(chuàng)建Handler的代碼 (適用于處理單一情況)

 /**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     * 
     * @return Returns true if the Runnable was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

2.sendMessage(Message)

sendMessage有多種發(fā)送消息的方式,有發(fā)送空數(shù)據(jù)和延遲兩個(gè)屬性,根據(jù)具體的情況選擇和合適的方式
而且能發(fā)送不同類型消息,在handlMessage中處理。(適用于多種情況)

三、Handler內(nèi)部機(jī)制

  • Message:Hanler接收和處理的消息對(duì)象。
  • MessageQueue:消息隊(duì)列,使用FIFO(先進(jìn)先出)的方式管理Message。創(chuàng)建Loop對(duì)象是,也會(huì)在構(gòu)造器中創(chuàng)建MessageQuene對(duì)象
 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
  • Looper:每個(gè)線程只能擁有一個(gè)Looper,Looper的主要作用是負(fù)責(zé)讀取MessageQueen的Message,讀到的Message發(fā)送給Handler來處理。
  • Handler:發(fā)送和處理消息,Handler正常工作必須在當(dāng)前線程中擁有一個(gè)MessageQueen隊(duì)列和管理MessageQueen的Looper
  • 在UI線程中已經(jīng)初始化一個(gè)Message和Looper,直接創(chuàng)建Handler即可以處理消息
  • 新的線程中必須Looper.prepare();創(chuàng)建MessageQueen和Looper,然后 Looper.loop();方法啟動(dòng)
new Thread(new Runnable() {
            @Override
            public void run() {
               try {
                        Looper.prepare();
                        sendHandler = new Handler() {
                            @Override
                            public void handleMessage(Message msg) {
                                // TODO
                            }
                        };
                        Looper.loop();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }).start();

Looper.loop();的作用是通過死循環(huán)的方式不斷地從MessageQueen中讀取消息

四、Handler引起的內(nèi)存泄漏以及解決方案

原因:在java中非靜態(tài)內(nèi)部類和匿名內(nèi)部類都會(huì)隱式持有當(dāng)前類的外部引用,由于Handler是非靜態(tài)內(nèi)部類所以其持有當(dāng)前Activity的隱式引用,如果Handler沒有被釋放,其所持有的外部引用也就是Activity也不可能被釋放,因此造成內(nèi)存泄漏。比如Hander中延遲5min發(fā)送消息,在MessaageQueen中隊(duì)列中持有Hander引用,這隊(duì)列間接持有Activity引用
解決辦法:

  • 使用靜態(tài)內(nèi)部類,對(duì)Activity進(jìn)行弱引用
  private static class MyHandler extends Handler{
        //持有弱引用HandlerActivity,GC回收時(shí)會(huì)被回收掉.
        private final WeakReference<HandlerActivity> mActivty;
        public MyHandler(HandlerActivity activity){
            mActivty =new WeakReference<HandlerActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity=mActivty.get();
            super.handleMessage(msg);
            if(activity!=null){
                //執(zhí)行業(yè)務(wù)邏輯
            }
        }
    }
    private static final Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //執(zhí)行我們的業(yè)務(wù)邏輯
        }
    };
 
  • 在onDestroy()中,四messageQueenqi清空
    serHandler.removeCallbacksAndMessages(null);

五、如何使用Handler讓子線程與子線程之間進(jìn)行通信

1.創(chuàng)建兩個(gè)子線程,分別在子線程內(nèi)創(chuàng)建Hander對(duì)象
2.分別在子線程內(nèi)發(fā)送消息

  • 因?yàn)長(zhǎng)ooper.loop()是阻塞線程的因此在loop()之前發(fā)送消息
  • 如果構(gòu)造時(shí)不提供Looper類對(duì)象參數(shù),會(huì)獲取當(dāng)前線程的Looper對(duì)象
最后編輯于
?著作權(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)容

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