Message:消息;其中包含了消息ID,消息對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理
Handler:處理者;負責Message發送消息及處理。Handler通過與Looper進行溝通,從而使用Handler時,需要實現handlerMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等(主線程中才行)
MessageQueue:消息隊列;用來存放Handler發送過來的消息,並按照FIFO(先入先出隊列)規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等Looper的抽取。
Looper:消息泵,不斷從MessageQueue中抽取Message執行。因此,一個線程中的MessageQueue需要一個Looper進行管理。Looper是當前線程創建的時候產生的(UI Thread即主線程是系統幫忙創建的Looper,而如果在子線程中,需要手動在創建線程後立即創建Looper[調用Looper.prepare()方法])。也就是說,會在當前線程上綁定一個Looper對象。
Thread:線程;負責調度消息循環,即消息循環的執行場所。
知識要點
一、說明
1、handler應該由處理消息的線程創建。
2、handler與創建它的線程相關聯,而且也只與創建它的線程相關聯。handler運行在創建它的線程中,所以,如果在handler中進行耗時的操作,會阻塞創建它的線程。
二、一些知識點
1、Android的線程分爲有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper。主線程(UI線程)就是一個消息循環的線程。
2、獲取looper:
Looper.myLooper(); //獲得當前的Looper
Looper.getMainLooper() //獲得UI線程的Lopper
3、Handle的初始化函數(構造函數),如果沒有參數,那麼他就默認使用的是當前的Looper,如果有Looper參數,就是用對應的線程的Looper。
4、如果一個線程中調用Looper.prepare(),那麼系統就會自動的爲該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。
消息處理機制原理:
在創建Activity之前,當系統啓動的時候,先加載ActivityThread這個類,在這個類中的main函數,調用了Looper.prepareMainLooper();方法進行初始化Looper對象;然後創建了主線程的handler對象(Tips:加載ActivityThread的時候,其內部的Handler對象[靜態的]還未創建);隨後才創建了ActivityThread對象;最後調用了Looper.loop();方法,不斷的進行輪詢消息隊列的消息。也就是說,在ActivityThread和Activity創建之前(同樣也是Handler創建之前,當然handler由於這兩者初始化),就已經開啓了Looper的loop()方法,不斷的進行輪詢消息。需要注意的是,這個輪詢的方法是阻塞式的,沒有消息就一直等待(實際是等着MessageQueue的next()方法返回消息)。在應用一執行的時候,就已經開啓了Looper,並初始化了Handler對象。此時,系統的某些組件或者其他的一些活動等發送了系統級別的消息,這個時候主線程中的Looper就可以進行輪詢消息,並調用msg.target.dispatchMessage(msg)(msg.target即爲handler)進行分發消息,並通過handler的handleMessage方法進行處理;所以會優於我們自己創建的handler中的消息而處理系統消息。
0、準備數據和對象:
①、如果在主線程中處理message(即創建handler對象),那麼如上所述,系統的Looper已經準備好了(當然,MessageQueue也初始化了),且其輪詢方法loop已經開啓。【系統的Handler準備好了,是用於處理系統的消息】。【Tips:如果是子線程中創建handler,就需要顯式的調用Looper的方法prepare()和loop(),初始化Looper和開啓輪詢器】
②、通過Message.obtain()準備消息數據(實際是從消息池中取出的消息)
③、創建Handler對象,在其構造函數中,獲取到Looper對象、MessageQueue對象(從Looper中獲取的),並將handler作爲message的標籤設置到msg.target上
1、發送消息:sendMessage():通過Handler將消息發送給消息隊列
2、給Message貼上handler的標籤:在發送消息的時候,爲handler發送的message貼上當前handler的標籤
3、開啓HandlerThread線程,執行run方法。
4、在HandlerThread類的run方法中開啓輪詢器進行輪詢:調用Looper.loop()方法進行輪詢消息隊列的消息
【Tips:這兩步需要再斟酌,個人認爲這個類是自己手動創建的一個線程類,Looper的開啓在上面已經詳細說明了,這裏是說自己手動創建線程(HandlerThread)的時候,纔會在這個線程中進行Looper的輪詢的】
5、在消息隊列MessageQueue中enqueueMessage(Message msg, long when)方法裏,對消息進行入列,即依據傳入的時間進行消息入列(排隊)
6、輪詢消息:與此同時,Looper在不斷的輪詢消息隊列
7、在Looper.loop()方法中,獲取到MessageQueue對象後,從中取出消息(Message msg = queue.next())
8、分發消息:從消息隊列中取出消息後,調用msg.target.dispatchMessage(msg);進行分發消息
9、將處理好的消息分發給指定的handler處理,即調用了handler的dispatchMessage(msg)方法進行分發消息。
10、在創建handler時,複寫的handleMessage方法中進行消息的處理
11、回收消息:在消息使用完畢後,在Looper.loop()方法中調用msg.recycle(),將消息進行回收,即將消息的所有字段恢復爲初始狀態。
二、詳細解釋:
1、準備Looper對象
兩種情況初始化Looper對象:
1)在主線程中不需要顯式的創建Looper對象,直接創建Handler對象即可;因爲在主線程ActivityThread的main函數中已經自動調用了創建Looper的方法:Looper.prepareMainLooper();,並在最後調用了Looper.loop()方法進行輪詢。
2)如果在子線程中創建Handler對象,需要創建Looper對象,即調用顯式的調用Looper.prepare()
初始化Looper的工作:
1)初始化Looper對象:通過調用Looper.prepare()初始化Looper對象,在這個方法中,新創建了Looper對象;在創建Looper的同時,(在其構造函數中)也初始化了MessageQueue。
2)將Looper綁定到當前線程:在初始化中,調用sThreadLocal.set(new Looper(quitAllowed))方法,將其和ThreadLocal進行綁定
在ThreadLocal對象中的set方法,是將當前線程和Looper綁定到一起:首先獲取到當前的線程,並獲取線程內部類Values,通過Thread.Values的put方法,將當前線程和Looper對象進行綁定到一起。即將傳入的Looper對象掛載到當前線程上。
Tips:在Looper對象中,可以通過getThread()方法,獲取到當前線程,即此Looper綁定的線程對象。
源代碼:
Looper中:
- public static void prepare() {
- prepare(true);
- }
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mRun = true;
- mThread = Thread.currentThread();
- }
ThreadLocal中:
- public void set(T value) {
- Thread currentThread = Thread.currentThread();
- Values values = values(currentThread);
- if (values == null) {
- values = initializeValues(currentThread);
- }
- values.put(this, value);
- }
2、創建消息Message:
消息的創建可以通過兩種方式:
1)new Message()
2)Message.obtain():【當存在多個handler的時候,可以通過Message.obtain(Handler handler)創建消息,指定處理的handler對象】
Tips:建議使用第二種方式更好一些。原因:
因爲通過第一種方式,每有一個新消息,都要進行new一個Message對象,這會創建出多個Message,很佔內存。
而如果通過obtain的方法,是從消息池sPool中取出消息。每次調用obtain()方法的時候,先判斷消息池是否有消息(if (sPool != null)),沒有則創建新消息對象,有則從消息池中取出消息,並將取出的消息從池中移除【具體看obtain()方法】
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
- public Message() {
- }
3、創建Handler對象
兩種形式創建Handler對象:
1)創建無參構造函數的Handler對象:
2)創建指定Looper對象的Handler對象
最終都會調用相應的含有Callback和boolean類型的參數的構造函數
【這裏的Callback是控制是否分發消息的,其中含有一個返回值爲boolean的handleMessage(Message msg)方法進行判斷的;
boolean類型的是參數是判斷是否進行異步處理,這個參數默認是系統處理的,我們無需關心】
在這個構造函數中,進行了一系列的初始化工作:
①、獲取到當前線程中的Looper對象
②、通過Looper對象,獲取到消息隊列MessageQueue對象
③、獲取Callback回調對象
④、獲取異步處理的標記
源代碼:
①、創建無參構造函數的Handler對象:
- public Handler() {
- this(null, false);
- }
- 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());
- }
- }
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
②、創建指定Looper對象的Handler對象
- public Handler(Looper looper) {
- this(looper, null, false);
- }
- public Handler(Looper looper, Callback callback, boolean async) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
4、Handler對象發送消息:
1)Handler發送消息給消息隊列:
Handler對象通過調用sendMessage(Message msg)方法,最終將消息發送給消息隊列進行處理
這個方法(所有重載的sendMessage)最終調用的是enqueueMessage(MessageQueuequeue, Message msg, long uptimeMillis)
(1)先拿到消息隊列:在調用到sendMessageAtTime(Messagemsg, long uptimeMillis)方法的時候,獲取到消息隊列(在創建Handler對象時獲取到的)
(2)當消息隊列不爲null的時候(爲空直接返回false,告知調用者處理消息失敗),再調用處理消息入列的方法:
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
這個方法,做了三件事:
①、爲消息打上標籤:msg.target = this;:將當前的handler對象這個標籤貼到傳入的message對象上,爲Message指定處理者
②、異步處理消息:msg.setAsynchronous(true);,在asyn爲true的時候設置
③、將消息傳遞給消息隊列MessageQueue進行處理:queue.enqueueMessage(msg, uptimeMillis);
- public final boolean sendMessage(Message msg){
- return sendMessageDelayed(msg, 0);
- }
- public final boolean sendMessageDelayed(Message msg, long delayMillis){
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- 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);
- }
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
2)MessageQueue消息隊列處理消息:
在其中的enqueueMessage(Messagemsg, long when)方法中,工作如下:
在消息未被處理且handler對象不爲null的時候,進行如下操作(同步代碼塊中執行)
①、將傳入的處理消息的時間when(即爲上面的uptimeMillis)賦值爲當前消息的when屬性。
②、將next()方法中處理好的消息賦值給新的消息引用:Message p =mMessages;
在next()方法中:不斷的從消息池中取出消息,賦值給mMessage,當沒有消息發來的時候,Looper的loop()方法由於是阻塞式的,就一直等消息傳進來
③、當傳入的時間爲0,且next()方法中取出的消息爲null的時候,將傳入的消息msg入列,排列在消息隊列上,此時爲消息是先進先出的
否則,進入到死循環中,不斷的將消息入列,根據消息的時刻(when)來排列發送過來的消息,此時消息是按時間的先後進行排列在消息隊列上的
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.isInUse()) {
- throw new AndroidRuntimeException(msg + " This message is already in use.");
- }
- if (msg.target == null) {
- throw new AndroidRuntimeException("Message must have a target.");
- }
- boolean needWake;
- synchronized (this) {
- if (mQuiting) {
- RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- }
- msg.when = when;
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
- // New head, wake up the event queue if blocked.
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
- needWake = mBlocked && p.target == null && msg.isAsynchronous();
- Message prev;
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
- }
- msg.next = p; // invariant: p == prev.next
- prev.next = msg;
- }
- }
- if (needWake) {
- nativeWake(mPtr);
- }
- return true;
- }
5、輪詢Message
1)開啓loop輪詢消息
當開啓線程的時候,執行run方法,在HandlerThread類中,調用的run方法中將開啓loop進行輪詢消息隊列:
在loop方法中,先拿到MessageQueue對象,然後死循環不斷從隊列中取出消息,當消息不爲null的時候,通過handler分發消息:msg.target.dispatchMessage(msg)。消息分發完之後,調用msg.recycle()回收消息,
2)回收消息:
在Message的回收消息recycle()這個方法中:首先調用clearForRecycle()方法,將消息的所有字段都恢復到原始狀態【如flags=0,what=0,obj=null,when=0等等】
然後在同步代碼塊中將消息放回到消息池sPool中,重新利用Message對象
源代碼:
Looper.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;
- }
- // This must be in a local variable, in case a UI event sets the logger
- Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- msg.target.dispatchMessage(msg);
- if (logging != null) {
- logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
- }
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf(TAG, “……”);
- }
- msg.recycle();
- }
- }
msg.recycle();:
- public void recycle() {
- clearForRecycle();
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
- /*package*/ void clearForRecycle() {
- flags = 0;
- what = 0;
- arg1 = 0;
- arg2 = 0;
- obj = null;
- replyTo = null;
- when = 0;
- target = null;
- callback = null;
- data = null;
- }
6、處理Message
在Looper.loop()方法中調用了msg.target.dispatchMessage(msg);的方法,就是調用了Handler中的dispatchMessage(Message msg)方法:
1)依據Callback中的handleMessage(msg)的真假判斷是否要處理消息,如果是真則不進行消息分發,則不處理消息,否則進行處理消息
2)當Callback爲null或其handleMessage(msg)的返回值爲false的時候,進行分發消息,即調用handleMessage(msg)處理消息【這個方法需要自己複寫】
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- /**
- * Handle system messages here.
- */
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }