Android——Handler原始碼分析
從原始碼分析Handler
1、APP的入口 ActivityThread 類的 main()方法,在main方法中呼叫了 Looper.prepareMainLooper();
public static void main(String[] args) {
//....省略
//Looper的初始化
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//開始訊息輪循
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2、Looper.prepareMainLooper()中呼叫了 prepare(false);方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//quitAllowed 表示是否可以退出此 Looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//ThreadLocal和 Looper的繫結,即當前執行緒和Looper繫結
sThreadLocal.set(new Looper(quitAllowed));
}
3、prepare(false)方法中呼叫 sThreadLocal.set(new Looper(quitAllowed));
完成了 ThreadLocal和 Looper的繫結,即當前執行緒和Looper繫結。
sThreadLocal.set(new Looper(quitAllowed));
//sThreadLocal是Looper的靜態成員變數
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
4、Looper的構造方法中 初始化了 MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
5、以上四步完成了 Looper、MessageQueue和ThreadLocal的初始化,
6、在main()方法的最後呼叫了 Looper.loop()方法,這個方法內部是一個死迴圈,這個時候主執行緒的訊息處理機制就執行起來了。
public static void loop() {
final Looper me = myLooper();
//...省略
for (;;) {
Message msg = queue.next(); // might block可能阻塞,queue.next()取出訊息
//...省略
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//在這裡由target(即handler)分發訊息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...省略
msg.recycleUnchecked();
}
}
7、建立Handler物件,在handler的構造方法中,如果 mLooper 為空,則會丟擲異常。
注意:在子執行緒中建立Handler物件時,要先呼叫 Looper.prepare()方法,完成Looper的初始化,從原始碼中分析,每個執行緒只允許有一個Looper。
public Handler() {
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 = null;
}
8、Handler傳送訊息,最終會呼叫到sendMessageAtTime(Message msg, long uptimeMillis)方法,uptimeMillis引數則表示傳送訊息的時間,它的值等於自系統開機到當前時間的毫秒數再加上延遲時間,SystemClock.uptimeMillis() + delayMillis。如果你呼叫的不是sendMessageDelayed()方法,延遲時間就為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);//把訊息加入到訊息佇列(訊息入隊的方法)
}
9、入隊其實就是將所有的訊息按時間來進行排序
//把訊息加入到訊息佇列(訊息入隊的方法)
enqueueMessage(queue, msg, uptimeMillis);
10、訊息出隊方法即 Message msg = queue.next();
// might block可能阻塞,queue.next()取出訊息。
訊息處理即 msg.target.dispatchMessage(msg);
//在這裡由target(即handler)分發訊息。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
11、一個標準的非同步執行緒 訊息處理寫法:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
12、另外除了傳送訊息之外,我們還有以下幾種方法可以在子執行緒中進行UI操作:
1. Handler的post()方法
2. View的post()方法(內部實際上也是呼叫的 Handler的post()方法)
3. Activity的runOnUiThread()方法(內部實際上也是呼叫的 Handler的post()方法)
handler.post的原始碼:
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; //直接把傳入的Runnable物件作為callback
return m;
}
在dispatchMessage()方法中,
if (msg.callback != null) {
handleCallback(msg);
}
private static void handleCallback(Message message) {
message.callback.run();//即由Runnable自行處理message
}
Android中為什麼主執行緒不會因為Looper.loop()裡的死迴圈卡死
參考:https://www.zhihu.com/question/34652589
HandlerThread——可迴圈子執行緒
1、HandlerThread繼承自Thread,它的run()中通過Looper.prepare()建立了訊息佇列,並通過Looper.loop()開啟了訊息迴圈。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
2、使用方法:
//1、建立HandlerThread
HandlerThread handlerThread = new HandlerThread("workHandlerThread");
handlerThread.start();
//2、獲取獲取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
//3、 建立Handler,通過Looper初始化
Handler childHandler = new Handler(looper,mCallback);
//4、投放非同步耗時任務到HandlerThread中
// childHandler.sendEmptyMessage(0);
//4、關閉訊息佇列,釋放執行緒資源
handlerThread.quit() ;
public class HandlerThreadTestActivity extends BaseActivity {
private HandlerThread handlerThread;//子執行緒
private Handler childHandler;//與子執行緒關聯的Handler
private Handler.Callback callback = new Handler.Callback() {
//子執行緒處理耗時操作的回撥
@Override
public boolean handleMessage(Message msg) {
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread_test);
initHandlerThread();
getData();
}
private void initHandlerThread() {
handlerThread = new HandlerThread("child_thread"); //構造引數為子執行緒的執行緒名
handlerThread.start();//開啟子執行緒
childHandler = new Handler(handlerThread.getLooper(),callback);//初始化子執行緒的Handler
}
private void getData() {
//投放非同步耗時任務到HandlerThread中
childHandler.sendEmptyMessage(0);
}
@Override
protected void onDestroy() {
super.onDestroy();
//釋放資源
handlerThread.quit() ;
}
}
3、使用HandlerThread的好處
3.1、HandlerThread將loop轉到子執行緒中處理,說白了就是將分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。
3.2、HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。
3.3、開啟一個執行緒起到多個執行緒的作用。處理任務是序列執行,按訊息傳送順序進行處理
4、HandlerThread的使用情景
5、Handler 和 Timer
IntentService 內部封裝的就是 HandlerThread
IntentService 是繼承於 Service 並處理非同步請求的一個類,在 IntentService 內有一個工作執行緒來處理耗時操作,啟動 IntentService 的方式和啟動傳統 Service 一樣,同時,當任務執行完後,IntentService 會自動停止,而不需要我們去手動控制。另外,可以啟動 IntentService 多次,而每一個耗時操作會以工作佇列的方式在IntentService 的 onHandleIntent 回撥方法中執行,並且,每次只會執行一個工作執行緒,執行完第一個再執行第二個,以此類推。
所有請求都在一個單執行緒中(HandlerThread),不會阻塞應用程式的主執行緒(UI Thread),同一時間只處理一個請求。
使用IntentService的好處:
1、我們省去了在 Service 中手動開執行緒的麻煩,
2、當操作完成時,我們不用手動停止 Service。
相關文章
- Android 原始碼分析(二)handler 機制Android原始碼
- Handler原始碼分析原始碼
- Android Handler 原始碼探索Android原始碼
- Android Handler 原始碼解析Android原始碼
- Android 8.1 Handler 原始碼解析Android原始碼
- Android原始碼學習之handlerAndroid原始碼
- Android--Handler機制及原始碼詳解Android原始碼
- Android Handler訊息機制原始碼解讀Android原始碼
- Android 9.0 原始碼_機制篇 -- 全面解析 HandlerAndroid原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Handler原始碼剖析原始碼
- Handler全家桶之 —— Handler 原始碼解析原始碼
- Android Choreographer 原始碼分析Android原始碼
- Handler原始碼解讀原始碼
- Handler系列原始碼解析原始碼
- Android中IntentService原始碼分析AndroidIntent原始碼
- android IO Prefetch原始碼分析Android原始碼
- Android開源原始碼分析Android原始碼
- Android多執行緒之Handler、Looper與MessageQueue原始碼解析Android執行緒OOP原始碼
- android原始碼學習-Handler機制及其六個核心點Android原始碼
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- 從原始碼去理解Handler原始碼
- Android原始碼分析–ArrayMap優化Android原始碼優化
- Android Sensor原始碼分析總結Android原始碼
- Android 8.0 原始碼分析 (八) ActivityManagerServiceAndroid原始碼
- Android Jetpack系列——ViewModel原始碼分析AndroidJetpackView原始碼
- Android 系統原始碼-1:Android 系統啟動流程原始碼分析Android原始碼
- React Native 0.55.4 Android 原始碼分析(Java層原始碼解析)React NativeAndroid原始碼Java
- 從原始碼角度來讀Handler原始碼
- Android Activity啟動流程原始碼分析Android原始碼
- Android系統原始碼分析之-ContentProviderAndroid原始碼IDE
- Android系統原始碼分析-事件收集Android原始碼事件
- Android View 事件分發原始碼分析AndroidView事件原始碼
- Android 7 原始碼分析系列導讀Android原始碼
- Android原始碼分析:Activity啟動流程Android原始碼
- Android View繪製原始碼分析 MeasureAndroidView原始碼
- Android Handler原理Android
- Android中HandlerAndroid
- Android原始碼分析(LayoutInflater.from(this).inflate(resId,null);原始碼解析)Android原始碼Null