Android--異步消息處理機(jī)制(Handler、Looper、Message、MessageQueue)

美女圖集03
Handler的由來

當(dāng)程序第一次啟動(dòng)的時(shí)候,Android會(huì)同時(shí)啟動(dòng)一條主線程(Main Thread)來負(fù)責(zé)處理與UI相關(guān)的事件,我們叫做UI線程
Android的UI操作并不是線程安全的(出于性能優(yōu)化考慮),意味著如果多個(gè)線程并發(fā)操作UI線程,可能導(dǎo)致線程安全問題。
為了解決Android應(yīng)用多線程問題——Android平臺(tái)只允許U線程修改Activity里的UI組件,就會(huì)導(dǎo)致新啟動(dòng)的線程無法改變界面組件的屬性值。
簡(jiǎn)單總結(jié):當(dāng)主線程隊(duì)列處理一個(gè)消息超過5秒,android就會(huì)拋出一個(gè)ANR(無響應(yīng))的異常,所以,我們需要把一些要處理時(shí)間比較長(zhǎng)的消息,放在一個(gè)單獨(dú)線程里面進(jìn)行處理,把處理以后的結(jié)果,返回給主線程運(yùn)行,就需要用到Handler來進(jìn)行線程組件的通信。

Handler的作用
  • 讓線程延時(shí)執(zhí)行,主要用到兩個(gè)方法:
方法1:final boolean postAtTime(Runnable r, long uptimeMillis)
方法2:final boolean postDelayed(Runnable r, long delayMillis)```
* 讓任務(wù)在其他線程中執(zhí)行并返回結(jié)果,分為兩個(gè)步驟:
**1.在新啟動(dòng)的線程中發(fā)送消息**
使用Handler對(duì)象的```sendMessage()```方法或者```sendEmptyMessage()```方法發(fā)送消息。
**2.在主線程中獲取處理消息**
重寫Handler類中處理消息的方法(void handleMessage(Message msg)),當(dāng)新啟動(dòng)的線程發(fā)送消息時(shí),消息發(fā)送到與之關(guān)聯(lián)的MessageQueue。而Handler不斷地從MessageQueue中獲取并處理消息。
#####Handler更新UI線程一般使用
(1):首先要進(jìn)行Handler聲明,復(fù)用handleMessage方法(放在主線程中)

private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO 接收消息并且去更新UI線程上的控件內(nèi)容
if (msg.what == UPDATE) {
// 更新界面上的textview
tv.setText(String.valueOf(msg.obj));
}
super.handleMessage(msg);
}
};```
(2):子線程發(fā)送Message給UI線程表示自己任務(wù)已經(jīng)執(zhí)行完成,主線程可以做相應(yīng)的操作了。

new Thread() {
       @Override
       public void run() {
          // TODO 子線程中通過handler發(fā)送消息給handler接收
                  //,由handler去更新TextView的值
          try {
              //do something
            
              Message msg = new Message();
              msg.what = UPDATE;                    
              msg.obj = "更新后的值" ;
              handler.sendMessage(msg);
          } catch (InterruptedException e) {
           e.printStackTrace();
          }
       }
 }.start();```

#####Handler原理分析
* **Handler的構(gòu)造函數(shù)**

1: public Handler()
2: public Handler(Callback callback)
3: public Handler(Looper looper)
4: public Handler(Looper looper, Callback callback) ```
第①個(gè)和第②個(gè)構(gòu)造函數(shù)都沒有傳遞Looper,這兩個(gè)構(gòu)造函數(shù)都將通過調(diào)用Looper.myLooper()獲取當(dāng)前線程綁定的Looper對(duì)象,然后將該Looper對(duì)象保存到名為mLooper的成員字段中。     
下面來看①②個(gè)函數(shù)源碼:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }

    //他們會(huì)調(diào)用Handler的內(nèi)部構(gòu)造方法
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() ||klass.isMemberClass()
                                         || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                  Log.w(TAG, "The following Handler class should be 
                                   static or leaks might occur: " +
                    klass.getCanonicalName());
             }
        }

        //重點(diǎn):Looper.myLooper()獲取了當(dāng)前線程保存的Looper實(shí)例
        mLooper = Looper.myLooper();

        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not 
                                       called Looper.prepare()");
        }
        //重點(diǎn):獲取MessageQueue(消息隊(duì)列)
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }```
**通過Looper.myLooper()獲取了當(dāng)前線程保存的Looper實(shí)例,又通過這個(gè)Looper實(shí)例獲取了其中保存的MessageQueue(消息隊(duì)列)。每個(gè)Handler對(duì)應(yīng)一個(gè)Looper對(duì)象,產(chǎn)生一個(gè)MessageQueue**
第③個(gè)和第④個(gè)構(gòu)造函數(shù)傳遞了Looper對(duì)象,這兩個(gè)構(gòu)造函數(shù)會(huì)將該Looper保存到名為mLooper的成員字段中。   
下面來看③④個(gè)函數(shù)源碼:
public Handler(Looper looper) {
    this(looper, null, false);
} 

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

//他們會(huì)調(diào)用Handler的內(nèi)部構(gòu)造方法
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
第②個(gè)和第④個(gè)構(gòu)造函數(shù)還傳遞了Callback對(duì)象,Callback是Handler中的內(nèi)部接口,需要實(shí)現(xiàn)其內(nèi)部的handleMessage方法,Callback代碼如下:

public interface Callback {
public boolean More ...handleMessage(Message msg);
}```
Handler.Callback是用來處理Message的一種手段,如果沒有傳遞該參數(shù),那么就應(yīng)該重寫Handler的handleMessage方法,也就是說為了使得Handler能夠處理Message,我們有兩種辦法:
方法1:向Hanlder的構(gòu)造函數(shù)傳入一個(gè)Handler.Callback對(duì)象,并實(shí)現(xiàn)Handler.Callback的handleMessage方法
方法2:無需向Hanlder的構(gòu)造函數(shù)傳入Handler.Callback對(duì)象,但是需要重寫Handler本身的handleMessage方法        
也就是說無論哪種方式,我們都得通過某種方式實(shí)現(xiàn)handleMessage方法,這點(diǎn)與Java中對(duì)Thread的設(shè)計(jì)有異曲同工之處。

  • Handle發(fā)送消息的幾個(gè)方法源碼
//發(fā)送消息
public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
 }```

//發(fā)送空消息,并且?guī)в袝r(shí)間延遲
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}```

//發(fā)送消息,并且?guī)в袝r(shí)間延遲
 public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, 
                SystemClock.uptimeMillis() + delayMillis);
}```

//發(fā)送消息,并且?guī)в芯唧w的時(shí)間限定
public boolean sendMessageAtTime(Message msg, long uptimeMillis){
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}```
我們可以看出他們最后都調(diào)用了sendMessageAtTime(),然后返回了enqueueMessage方法,下面看一下此方法源碼:

    private boolean enqueueMessage(MessageQueue queue
                                    , Message msg, long uptimeMillis) {
     //把當(dāng)前的handler作為msg的target屬性
          msg.target = this;
         if (mAsynchronous) {
              msg.setAsynchronous(true);
         }
         return queue.enqueueMessage(msg, uptimeMillis);
    }```
在該方法中有兩件事需要注意:
**1. msg.target = this;**該代碼將Message的target綁定為當(dāng)前的Handler
**2. queue.enqueueMessage **
變量queue表示的是Handler所綁定的消息隊(duì)列MessageQueue,通過queue.enqueueMessage(msg,uptimeMillis)我們將Message放入到消息隊(duì)列中。
下面通過一張圖,來看完整的方法調(diào)用順序:
![Handler、Looper、Message、MessageQueue調(diào)用順序](http://upload-images.jianshu.io/upload_images/3416944-d9d3d3505b4ba800.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

#####Looper原理分析
我們一般在主線程聲明Handler,有時(shí)我們需要繼承Thread類實(shí)現(xiàn)自己的線程功能,當(dāng)我們?cè)诶锩媛暶鱄andler的時(shí)候會(huì)報(bào)錯(cuò)。其原因是主線程中已經(jīng)實(shí)現(xiàn)了兩個(gè)重要的Looper方法,下面看一看ActivityThread.java中main方法的源碼:

public static void main(String[] args) {
//......省略
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop
unexpectedly exited");
}```

  • 首先看prepare()方法
     public static void prepare() {
         prepare(true);
     }

     private static void prepare(boolean quitAllowed) {
     //證明了一個(gè)線程中只有一個(gè)Looper實(shí)例
         if (sThreadLocal.get() != null) {
             throw new RuntimeException("Only one Looper may be 
                                             created per thread");
         }
         sThreadLocal.set(new Looper(quitAllowed));
     }```
該方法會(huì)調(diào)用Looper構(gòu)造函數(shù)同時(shí)實(shí)例化出MessageQueue和當(dāng)前thread.
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
} 

public static MessageQueue myQueue() {
    return myLooper().mQueue;
}```

prepare()方法中通過ThreadLocal對(duì)象實(shí)現(xiàn)Looper實(shí)例與線程的綁定。(不清楚的可以查看 ThreadLocal的使用規(guī)則和源碼分析

  • loop()方法
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() 
                                       wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }

            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " 
                                        + msg.callback + ": " + msg.what);
            }
            //重點(diǎn)****
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " 
                                                         + msg.callback);
            }

            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) 
                                        + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
            msg.recycleUnchecked();
        }
    }```
首先looper對(duì)象不能為空,就是說loop()方法調(diào)用必須在prepare()方法的后面。
Looper一直在不斷的從消息隊(duì)列中通過MessageQueue的next方法獲取Message,然后通過代碼```msg.target.dispatchMessage(msg)```讓該msg所綁定的Handler執(zhí)行dispatchMessage()方法以實(shí)現(xiàn)對(duì)Message的處理。
Handler的dispatchMessage的源碼如下:

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}```
我們可以看到Handler提供了三種途徑處理Message,erqie處理有前后優(yōu)先級(jí)之分:首先嘗試讓postXXX()中傳遞的Runable執(zhí)行,其次嘗試讓Handler構(gòu)造函數(shù)中傳入的Callback的handleMessage()方法處理,最后才是讓Handler自身的handleMessage()方法處理Message。

如何在子線程中使用Handler

Handler本質(zhì)是從當(dāng)前的線程中獲取到Looper來監(jiān)聽和操作MessageQueue,當(dāng)其他線程執(zhí)行完成后回調(diào)當(dāng)前線程。
子線程需要先prepare()才能獲取到Looper對(duì)象,是因?yàn)樽泳€程只是一個(gè)普通的線程,其ThreadLoacl中沒有設(shè)置過Looper,所以會(huì)拋出異常,而在Looper的prepare()方法中sThreadLocal.set(new Looper())是設(shè)置了Looper的。

  • 實(shí)例代碼:定義一個(gè)類實(shí)現(xiàn)Runnable接口或繼承Thread類(一般不繼承)。
class Rub implements Runnable {  
        public Handler myHandler;  
        // 實(shí)現(xiàn)Runnable接口的線程體 
        @Override  
        public void run() {  
             /*1、調(diào)用Looper的prepare()方法為當(dāng)前線程創(chuàng)建Looper對(duì)象并,
            創(chuàng)建Looper對(duì)象時(shí),它的構(gòu)造器會(huì)自動(dòng)的創(chuàng)建相對(duì)應(yīng)的MessageQueue*/
             Looper.prepare();  
            
             /*2、創(chuàng)建Handler子類的實(shí)例,重寫HandleMessage()方法
                             ,該方法處理除當(dāng)前線程以外線程的消息*/
             myHandler = new Handler() {  
                @Override  
                public void handleMessage(Message msg) {  
                    String ms = "";  
                    if (msg.what == 0x777) {  
                     
                    }  
                }  
            };  
            //3、調(diào)用Looper的loop()方法來啟動(dòng)Looper讓消息隊(duì)列轉(zhuǎn)動(dòng)起來
            Looper.loop();  
        }
    }```
**注意分成三步:**
1:調(diào)用Looper的prepare()方法為當(dāng)前線程創(chuàng)建Looper對(duì)象,創(chuàng)建Looper對(duì)象時(shí),它的構(gòu)造器會(huì)創(chuàng)建與之配套的MessageQueue。
2:有了Looper之后,創(chuàng)建Handler子類實(shí)例,重寫HanderMessage()方法,該方法負(fù)責(zé)處理來自于其他線程的消息。
3:調(diào)用Looper的looper()方法啟動(dòng)Looper。然后使用這個(gè)handler實(shí)例在任何其他線程中發(fā)送消息,最終處理消息的代碼都會(huì)在你創(chuàng)建的Handler實(shí)例的線程中運(yùn)行。

#####總結(jié)
* **Handler**
發(fā)送消息,它能把消息發(fā)送給Looper管理的MessageQueue,Looper分發(fā)給它消息。
* **Message**
Handler接收和處理的消息對(duì)象。
* **Looper**
每個(gè)線程只有一個(gè)Looper,它負(fù)責(zé)管理對(duì)應(yīng)的MessageQueue,會(huì)不斷地從MessageQueue中取出消息,并將消息Messsge分發(fā)給對(duì)應(yīng)的Handler進(jìn)行處理。
主線程中,系統(tǒng)已經(jīng)初始化了一個(gè)Looper對(duì)象,因此可以直接創(chuàng)建Handler即可,就可以通過Handler來發(fā)送消息、處理消息。程序自己?jiǎn)?dòng)的子線程,程序必須自己創(chuàng)建一個(gè)Looper對(duì)象,bignqie啟動(dòng)它,調(diào)用Looper.prepare()方法。
* **prapare()方法**
保證每個(gè)線程最多只有一個(gè)Looper對(duì)象。
* **looper()方法**
啟動(dòng)Looper,使用一個(gè)死循環(huán)不斷取出MessageQueue中的消息,并將取出的消息分發(fā)給對(duì)應(yīng)的Handler進(jìn)行處理。
* **MessageQueue**
由Looper負(fù)責(zé)管理,它采用先進(jìn)先出的方式來管理Message。
* **Handler的構(gòu)造方法**
會(huì)首先得到當(dāng)前線程中保存的Looper實(shí)例,進(jìn)而與Looper實(shí)例中的MessageQueue相關(guān)聯(lián)。
* **Handler的sendMessage方法**
會(huì)給msg的target賦值為handler自身,然后加入MessageQueue中。

參考鏈接:
[線程通信基礎(chǔ)流程分析(Handler、Looper、Message、MessageQueue)](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/%E7%BA%BF%E7%A8%8B%E9%80%9A%E4%BF%A1%E5%9F%BA%E7%A1%80%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90.md)


**結(jié)束語:越努力,越幸運(yùn)!加油   ---王令
QQ:2585085940
郵箱:wang91ling@163.com
歡迎大家光臨寒舍。**
最后編輯于
?著作權(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)容