Android開發Handler原始碼分析
為什麼使用Handler
Android中UI控制元件的訪問是執行緒不安全的,加鎖同步訪問會影響效能,因此設定只能一個執行緒更新UI,就是主執行緒,或者說是UI執行緒。在UI執行緒中不能進行耗時的操作,耗時操作需要開啟一個新的工作執行緒,工作執行緒不能更新UI,因此工作執行緒通過Handler通知UI執行緒更新UI
Handler構造器分析
建立匿名Handler或者內部Handler的時候,IDE會提示記憶體洩露的風險,因為內部類持有外部類引用,修改為靜態內部類即可
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());
}
}
Handler內部幾個重要的屬性
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;
通過建構函式對屬性進行賦值。類屬性的命名規則以小寫字母m開頭,命名的規範值得學習。
其他幾個過載的建構函式功能類似,對類屬性的賦值。
通過Handler傳送訊息
Handler有多個傳送訊息的方法,但最終都呼叫了
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
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);
}
傳送訊息就是把訊息插入到訊息佇列,該訊息在訊息佇列的位置由該訊息處理的時間when決定
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在這裡將msg的target屬性設定為this,也就是當前的Handler,這點很重要,之後的訊息處理會用到。最終是呼叫了MessageQueue類的enqueueMessage方法
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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 {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
首先檢查了改msg的target屬性是不是null,也就是是否設定了處理該msg的Handler,沒有設定Handler就丟擲異常,同一個msg不能進佇列兩次,否則丟擲異常
通過了上邊兩項檢查後,設定msg已使用,設定msg的處理事件,為msg的when屬性賦值
msg.markInUse();
msg.when = when;
然後根據msg的when屬性和Message佇列的情況,將該msg插入到佇列合適的位置
Handler訊息的輪詢處理
訊息通過Handler的post和send方法加入了handler的訊息佇列MessageQueue,那麼訊息佇列中的訊息是如何被依次處理的呢?是通過Looper,Handler有兩個重要的屬性
final MessageQueue mQueue;
final Looper mLooper;
在上邊建構函式的分析中,看到mQueue是如何被賦值的
mQueue = mLooper.mQueue;
即Handler的訊息佇列就是Looper的訊息佇列,因此訊息的輪詢處理是交給了Looper。一個Looper和一個執行緒繫結,要想使一個執行緒具備Looper的能力(輪詢訊息佇列),需要線上程run方法開頭呼叫
private static void prepare(boolean quitAllowed)
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));
}
在prepare中通過ThreadLocal執行緒本地變數將Looper繫結到了呼叫prepare的執行緒。然後要想使執行緒具有輪詢能力,需要線上程run方法末尾呼叫
public static void 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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
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);
}
// Make sure that during the course of dispatching the
// 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();
}
}
可見在loop方法中通過死迴圈處理訊息佇列中的訊息
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
}
從訊息佇列中依次取出訊息,然後呼叫msg的target屬性的dispatchMessage方法。
而target是如何被賦值的呢?是在Handler呼叫post或者send傳送訊息的時候被賦值的,被賦值為傳送此訊息的handler
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
因此訊息的處理又回到了Handler執行緒,通過Handler的dispatchMessage方法回撥處理訊息
Handler處理訊息
在Handler所線上程,通過類似責任鏈模式的方式,處理該訊息
/**
* 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);
}
}
相關文章
- Android 原始碼分析(二)handler 機制Android原始碼
- Handler原始碼分析原始碼
- Android Handler 原始碼解析Android原始碼
- Android Handler 原始碼探索Android原始碼
- Android 8.1 Handler 原始碼解析Android原始碼
- Android原始碼學習之handlerAndroid原始碼
- Android開源原始碼分析Android原始碼
- Android 9.0 原始碼_機制篇 -- 全面解析 HandlerAndroid原始碼
- Android--Handler機制及原始碼詳解Android原始碼
- Android Handler訊息機制原始碼解讀Android原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Android View 事件分發原始碼分析AndroidView事件原始碼
- Handler原始碼剖析原始碼
- Handler全家桶之 —— Handler 原始碼解析原始碼
- Android Choreographer 原始碼分析Android原始碼
- Handler系列原始碼解析原始碼
- Handler原始碼解讀原始碼
- android IO Prefetch原始碼分析Android原始碼
- Android中IntentService原始碼分析AndroidIntent原始碼
- android原始碼學習-Handler機制及其六個核心點Android原始碼
- Android多執行緒之Handler、Looper與MessageQueue原始碼解析Android執行緒OOP原始碼
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- 從原始碼去理解Handler原始碼
- Android 8.0 原始碼分析 (八) ActivityManagerServiceAndroid原始碼
- Android Jetpack系列——ViewModel原始碼分析AndroidJetpackView原始碼
- Android原始碼分析–ArrayMap優化Android原始碼優化
- Android Sensor原始碼分析總結Android原始碼
- Android 系統原始碼-1:Android 系統啟動流程原始碼分析Android原始碼
- 基於原始碼分析 Android View 事件分發機制原始碼AndroidView事件
- React Native 0.55.4 Android 原始碼分析(Java層原始碼解析)React NativeAndroid原始碼Java
- 從原始碼角度來讀Handler原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析1(FMResultSet)iOS原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析2(FMResultSet)iOS原始碼
- Android原始碼角度分析事件分發消費(徹底整明白Android事件)Android原始碼事件
- Android View繪製原始碼分析 MeasureAndroidView原始碼
- Android Activity啟動流程原始碼分析Android原始碼
- Android系統原始碼分析之-ContentProviderAndroid原始碼IDE
- Android系統原始碼分析-事件收集Android原始碼事件
- Android 7 原始碼分析系列導讀Android原始碼