Handler原始碼分析
目錄
前言
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框架.
多執行緒同步.
相關文章
- Android——Handler原始碼分析Android原始碼
- 【Android原始碼】Handler 機制原始碼分析Android原始碼
- Android開發Handler原始碼分析Android原始碼
- Android 原始碼分析(二)handler 機制Android原始碼
- Android Handler機制使用,原始碼分析Android原始碼
- Handler原始碼剖析原始碼
- Handler原始碼解析原始碼
- Handler全家桶之 —— Handler 原始碼解析原始碼
- Handler系列原始碼解析原始碼
- Handler原始碼解讀原始碼
- Android Handler 原始碼解析Android原始碼
- 從原始碼去理解Handler原始碼
- Android Handler 原始碼探索Android原始碼
- 從原始碼角度來讀Handler原始碼
- Android 8.1 Handler 原始碼解析Android原始碼
- Android 原始碼分析 --Handler 機制的實現與工作原理Android原始碼
- Android原始碼學習之handlerAndroid原始碼
- Android執行緒間訊息機制-Handler原始碼分析(FrameWork)Android執行緒原始碼Framework
- 手把手帶你解析Handler原始碼原始碼
- 原始碼篇:Handler那些事(萬字長文)原始碼
- Handler原理分析
- Android原始碼解析Handler系列第(四)篇 --- 打破Handler那些困惑事兒Android原始碼
- Retrofit原始碼分析三 原始碼分析原始碼
- Netty原始碼解析4-Handler綜述Netty原始碼
- 原始碼深度解析 Handler 機制及應用原始碼
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- Handler 機制分析
- Android 9.0 原始碼_機制篇 -- 全面解析 HandlerAndroid原始碼
- SpringMVC請求對映handler原始碼解讀SpringMVC原始碼
- Android--Handler機制及原始碼詳解Android原始碼
- Handler訊息處理機制原始碼解析 上原始碼
- Android Handler訊息機制原始碼解讀Android原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼