Handler原始碼分析

fdsafwagdagadg6576發表於2020-12-16

目錄

前言

Handler使用,請參見:https://blog.csdn.net/fdsafwagdagadg6576/article/details/110293636

正文

一  整體框架

  • 總體流程
  • Handler通過sendMessage()傳送Message到MessageQueue佇列;
  • Looper通過loop(),不斷提取出達到觸發條件的Message,並將Message交給target來處理;
  • 經過dispatchMessage()後,交回給Handler的handleMessage()來進行相應地處理。
  • 將Message加入MessageQueue時,往管道寫入字元,可以會喚醒loop執行緒;

二 生產者消費者模型

模組執行緒
生產者子執行緒handler.sendmessage
消費者主執行緒 looper & handler.handlemessage
中介主執行緒 messageQueue

 

 

 

 

 

三 執行緒同步

1) 主執行緒和子執行緒讀寫同步,是messageQueued.next 通過epoll監聽messagequeue繫結的檔案fd,實現讀寫同步.
2) 子執行緒之間寫queue同步,是messageQueued.enqueueMessage中的鎖.

四 角色作用

角色

作用分層(activity入口--開發者使用--android系統層)
handler傳送和處理訊息開發者使用介面.
looper每個執行緒只能有一個Looper。messageQueue屬於它.
它的loop方法負責讀取MessageQueue中的訊息,讀到訊息後把訊息傳送給Handler進行處理。(執行緒和Looper繫結)
Activity入口函式建立&android 系統層使用
messagequeue先進先出的方式來管理msg.建立Looper物件時,會在它的構造方法中建立MessageQueue物件。(looper和messagequeue繫結)android 系統層使用
message訊息應用層

 

 

 

 

 

 

 


五 原始碼分析

1 Handler類

1.1 Handler 建構函式初始化
1) 無引數建構函式

public class Handler {
	/**我們通常用於建立Handler的構造方法之一*/
	public Handler() {
		this(null, false);
	}
	//=============step1: 建構函式====================
	public Handler(Callback callback, boolean async) {
        ......
        //=======step2:獲取Looper(messagequeue管理者)==============
        mLooper = Looper.myLooper();
        //=======step3: 獲取Looper的Messagequeue=====
        mQueue = mLooper.mQueue;  
        //回撥函式預設是Null  
        mCallback = callback; 
        //設定訊息是否為非同步處理方式 
        mAsynchronous = async; 
	}

根據呼叫關係:
step1:  Handler建構函式中會去建立一個Looper物件。handler和Looper繫結,同時繫結Looper的messageQueue。
step2:  Looper.myLooper()獲取Looper.
step3: mLooper.mQueue 獲取Looper的MessageQueue.

2) 有參建構函式

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

Handler類在構造方法中,可指定Looper,Callback回撥方法以及訊息的處理方式(同步或非同步),對於無參的handler,預設是當前執行緒的Looper。
mainHandler = new Handler() 等價於 new Handler(Looper.myLooper())
Looper.myLooper():獲取當前程式的looper物件。詳見下文.

1.2 Handler send message

call laddder:
sendEmptyMessage
--sendEmptyMessageDelayed
----sendMessageDelayed
------sendMessageAtTime
--------enqueueMessage
/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    ......
    return enqueueMessage(queue, msg, uptimeMillis);
}
// 最後呼叫此方法新增到訊息佇列中
private boolean enqueueMessage(MessageQueue queue, Message msg,long uptimeMillis) {
    msg.target = this;// 設定傳送目標物件是Handler本身
    ......
    return queue.enqueueMessage(msg, uptimeMillis);// 新增到訊息佇列中
}

step1: Message.obtain
step2:enqueueMessage(queue, msg, uptimeMillis)
step3:   msg.target = this;// 設定傳送目標物件是Handler本身
         return queue.enqueueMessage(msg, uptimeMillis);// 新增到訊息佇列中

1.3 訊息處理

case1: handleMessage(msg);
是派生一個Hanlder子類並重寫其handleMessage方法來處理具體的訊息。 
傳送發是sendMessage.
case 2:handleCallback & mCallback.handleMessage(msg)
用callback來建立一個Handler的例項而無需派生Handler的子類。而Callback給我們提供了另外一種方式,那就是當我們不想派生子類的時候,可以通過Callback來實現.

call ladder: 
post
--sendMessageDelayed
----getPostMessage
------m.callback = r//Runnable物件
--------new Handler(callback)

Message的callback是什麼?其實就是一個Runnable物件,實際上就是Handler的post方法所傳遞的Runnable引數

private static void handleCallback(Message message) {
        message.callback.run();
}

 傳送方:

public final boolean post(Runnable r)
{
       return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
}

最後要注意的是寫在Looper.loop()之後的程式碼不會被執行,這個函式內部應該是一個迴圈,當呼叫mHandler.getLooper().quit()後,loop()才會中止,其後的程式碼才能得以執行。

1.4 異常處理

記憶體洩漏

//檢查Handler是否是static的;如果不是的,那麼有可能導致記憶體洩露
        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());  
            }  
        }

2  Looper類

2.1 建立MessageQueue

//Looper類的構造方法建立了訊息佇列MessageQueue物件
private Looper(boolean quitAllowed) {
	mQueue = new MessageQueue(quitAllowed);
	mRun = true;
	mThread = Thread.currentThread();
}

一個執行緒一個Looper一個MessageQueue

2.2 獲取Looper物件

通過ThreadLocal獲取Looper物件

//handler呼叫的獲取Looper物件的方法。實際是在ThreadLocal中獲取。
	public static Looper myLooper() {
		return sThreadLocal.get();
	}

2.3 Looper 主迴圈

Looper 讀取message & 分發message

//looper中最重要的方法loop(),該方法是個死迴圈,會不斷去訊息佇列MessageQueue中獲取訊息,
//然後調dispatchMessage(msg)方法去執行
public static void loop() {
	    final Looper me = myLooper();
	    final MessageQueue queue = me.mQueue;
	    //進入loop的主迴圈方法
	    for (;;) {
		Message msg = queue.next(); // might block
        ......
        //msg.target is handler;分發訊息
		msg.target.dispatchMessage(msg);
		msg.recycle();
}
  • Message msg= queue.next() ; 讀取MessageQueue的下一條Message;
  • msg.target.dispatchMessage(msg);把Message分發給相應的target;

next原始碼分析,參見MessageQueue類分析
下面是dispatchMessage分析

// 在looper類中的loop()方法內部呼叫的方法
public void dispatchMessage(Message msg) {
	if (msg.callback != null) {
		handleCallback(msg);
	} else {
		if (mCallback != null) {
			if (mCallback.handleMessage(msg)) {
				return;
			}
		}
		handleMessage(msg);
	}

分發給handleMessage 和handleCallback 處理.

2.4 子執行緒建立Looper(擴充套件)

預設是在主執行緒中建立Looper,子執行緒使用的是主執行緒Looper.
ThreadLocal中set Looper並儲存到當前執行緒的TLS區域. 將執行緒和Looper繫結??
Looper建立的同時MessageQueue訊息佇列也被建立完成,Looper繫結MessageQueue物件。 

//perpare()方法,用來初始化一個Looper物件
public static void prepare() {
	prepare(true);
}		
private static void prepare(boolean quitAllowed) {
    ......
	sThreadLocal.set(new Looper(quitAllowed));
}

在非主執行緒中直接new Handler() 會報如下的錯誤:  Can't create handler inside thread that has not called Looper.prepare() 原因是非主執行緒中預設沒有建立Looper物件,需要先呼叫Looper.prepare()啟用Looper,然後再呼叫Looper.loop()。
子執行緒自己建立Looper

class childThread extends Thread{
        public Handler mHandler;
 
        @Override
        public void run() {
            //子執行緒中必須先建立Looper
            Looper.prepare();
            
            mHandler =new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //處理訊息
                }
            };
            //啟動looper迴圈
            Looper.loop();
        }
    }

三 MessageQueue類

 next() :提取下一條message.在這裡messagequeue 阻塞

Message next() {
    final long ptr = mPtr;
    ......
    for (;;) {
        //阻塞操作,當等待nextPollTimeoutMillis時長,或者訊息佇列被喚醒,都會返回
        nativePollOnce(ptr, nextPollTimeoutMillis);
    ......
    }
}

 messageQueue 從java-jni-native c++流程,參見:http://gityuan.com/2015/12/27/handler-message-native/

四 小結

知識點:生產者消費者模型.
一個執行緒一個Looper一個MessageQueue和多個handler框架.
多執行緒同步. 

 

 

相關文章