日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Handler消息处理机制

發(fā)布時(shí)間:2025/7/14 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Handler消息处理机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、核心類

1、Looper

1.變量

ThreadLocal sTreadLoad;

MesseageQuene mQueue;

Tread mThread;

2.操作集

Looper.Prepare();

Looper.loop();

2、Handler

變量

MessageQueue mQueue;

Looper mLooper;

CallBack mCallback;

操作集

//分發(fā)消息

dispatchMessage(Message msg);

//發(fā)送消息

sendMessage(Message msg)

3、Messeage

變量

int when;//發(fā)送時(shí)間(從開機(jī)到現(xiàn)在的時(shí)間,單位毫秒)

Handler target;//綁定的Handler對(duì)象

操作集

Handler getTarget();//獲取綁定的Handler對(duì)象

4、MesseageQueue

變量

Message mMessage;//鏈表的第一個(gè)節(jié)點(diǎn)

操作集

bolean enqueueMessage(Message msg, long when) ();//Messeage添加到鏈表 Message next() ;//從鏈表中取出Message

二、大體流程

使用Handler機(jī)制,首先需要在線程中調(diào)用Looper.prepare(),對(duì)Looper初始化,Looper初始化的同時(shí),內(nèi)部會(huì)對(duì)MessageQueue初始化,并持有MessageQueue對(duì)象;

創(chuàng)建Handler,并持有當(dāng)前線程中Looper和MessageQueue的引用;

Handler對(duì)象發(fā)送消息,將發(fā)送的Messeage與Handler綁定,加入MessageQueue中的鏈表中;

Looper.loop()循環(huán)地取出Messeage,調(diào)用與Messeage綁定的Handler對(duì)象的dispatchMessage方法分發(fā)處理消息;

三、源碼分析

1.Looper的初始化

Looper.prepare源碼如下:

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));} 復(fù)制代碼

首先判斷當(dāng)前Thread對(duì)應(yīng)的Looper對(duì)象是否為空,如果不為空的話,拋出異常:每個(gè)線程中只能有一個(gè)Looper對(duì)象;如果不為空的話,新建一個(gè)Looper對(duì)象,并保存在一個(gè)Looper與創(chuàng)建它的Thread相對(duì)應(yīng)的存儲(chǔ)結(jié)構(gòu)ThreadLocal中,ThreadLocal的實(shí)現(xiàn)暫且不表。

繼續(xù)看new Looper(quitAllowed)的實(shí)現(xiàn)源碼:

private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();} 復(fù)制代碼

Looper的構(gòu)造器中,創(chuàng)建類一個(gè)MesseageQueue對(duì)象,并獲取類當(dāng)前線程; 這樣,Looper對(duì)象就持有MesseageQueue對(duì)象;

而我們都知道,在子線程中需要手動(dòng)調(diào)用Looper的初始化,在主線程中是不需要我們手動(dòng)調(diào)用Looper.prepare()和Looper.looper()方法的,因?yàn)橄到y(tǒng)已經(jīng)調(diào)用過了,貼上調(diào)用源碼:

public static void main(String[] args) {//省略部分代碼Looper.prepareMainLooper();//省略部分代碼if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}復(fù)制代碼

啟動(dòng)的時(shí)候,ActivityThread的main()方法中調(diào)用了Looper.prepareMainLooper();main方法的末尾調(diào)用了Looper.loop()方法;

繼續(xù)查看Looper.prepareMainLooper()的源碼:

public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}} 復(fù)制代碼

首先調(diào)用了Looper的prepare方法進(jìn)行初始化,然后用一個(gè)同步,給sMainLooper賦值;

2.Handler的初始化

使用Handler,當(dāng)然要new 一個(gè)Handler對(duì)象,下面看一下Handler構(gòu)造器的源碼:

public Handler(Callback callback, boolean async) {//省略部分代碼mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;} 復(fù)制代碼

首先,會(huì)獲取到當(dāng)前線程的Looper對(duì)象,如果Looper對(duì)象為空,拋出異常:在線程內(nèi)沒有調(diào)用Looper.prepare(),不能創(chuàng)建Handler,這也就是之前說的,使用Looper機(jī)制,必須首先對(duì)looper進(jìn)行初始化。

如果Looper對(duì)象不為空的話,獲取的Looper已經(jīng)賦值給了mLooper,再獲取Looper中持有的MessageQueue對(duì)象(Looper初始化時(shí)創(chuàng)建)賦值給mQueue,這樣Handler就持有了當(dāng)前線程的Looper對(duì)象和相應(yīng)的MessageQueue對(duì)象,最后吧傳入的callback參數(shù)賦值給mCallBack;

3.Handler發(fā)送消息

Handler發(fā)送消息分為兩類,一類時(shí)sendMessage相關(guān)的,一類時(shí)post相關(guān)的;

首先查看sendMessage相關(guān)的方法源碼:

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);} 復(fù)制代碼

可以看出最終都是調(diào)用sendMessageAtTime方法,sendMessage表示當(dāng)前時(shí)間發(fā)送(SystemClock.uptimeMillis表示當(dāng)前時(shí)間到開機(jī)時(shí)間的毫秒數(shù)),sendMessageDelayed的時(shí)間為當(dāng)前時(shí)間在加上延遲的時(shí)間(delay的時(shí)間是負(fù)值是沒有意義的,不可能多長時(shí)間之前去處理消息,系統(tǒng)會(huì)修改為0),sendMessageAtTime如果輸入的時(shí)間參數(shù)小于當(dāng)前時(shí)間,也會(huì)按照現(xiàn)在發(fā)送來處理。

然后查看post相關(guān)的源碼

public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}public final boolean postAtTime(Runnable r, long uptimeMillis){return sendMessageAtTime(getPostMessage(r), uptimeMillis);}private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;} 復(fù)制代碼

很明顯,post最終也是調(diào)用sendMessage來實(shí)現(xiàn)的,只不過把Runnable參數(shù)賦值給了Message的callback變量(分發(fā)處理時(shí)用)。

4.Messeage如何與發(fā)送它的Handler綁定

sendMessageAtTime方法中,首先判斷MessageQueue是否為空,為空,拋出異常,返回;不為空,調(diào)用enqueueMessage(queue, msg, uptimeMillis);

繼續(xù)查看調(diào)用enqueueMessage的源碼:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);} 復(fù)制代碼

首先把this,也就是Handler對(duì)象賦值給Message的target變量,target是Handler類型,這樣就實(shí)現(xiàn)了Messeage與發(fā)送它Handler的綁定。

然后調(diào)用queue.enqueueMessage方法,將Message加入MessageQueue中。

5.Messeage如何加入到MessageQueue中

繼續(xù)追蹤enqueueMessage的源碼,查看是如何將Message加入到MessageQueue中的:

boolean enqueueMessage(Message msg, long when) {//省略部分代碼synchronized (this) {//省略部分代碼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 {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.nextprev.next = msg;}//省略部分代碼}return true;} 復(fù)制代碼

5.1 將參數(shù)when賦值給了Messeag的when,這個(gè)when參數(shù)也就是我們sendMessageAtTime的那個(gè)時(shí)間參數(shù);然后將Message p = mMessages(mMessage表示的是鏈表的頭節(jié)點(diǎn))。

5.2 判斷p是否為null,如果是null的話,說明鏈表中沒有節(jié)點(diǎn),也就是MessageQueue中沒有Message對(duì)象,直接把需要插入的msg做為頭節(jié)點(diǎn)賦值給mMessage,當(dāng)然msg.next = null,表示msg后面沒有結(jié)點(diǎn)了,然后返回。

5.3 如果p不為null,那就需要將msg插入到鏈表的合適位置,一個(gè)結(jié)點(diǎn)插入到鏈表中很容易實(shí)現(xiàn),關(guān)鍵是鏈表的結(jié)點(diǎn)是如何排序的。源碼中是否for循環(huán),一直查找下一個(gè)結(jié)點(diǎn),直到p == null 或 when < p.when是循環(huán)結(jié)束, p == null,也就是鏈表查找完畢,然后執(zhí)行【msg.next = p;prev.next = msg】把msg插入到了鏈表的最后;when<p.when,也就是說查找到了比when小的Message對(duì)象,然后執(zhí)行【msg.next = p;prev.next = msg】把msg插入到了pre結(jié)點(diǎn)和p結(jié)點(diǎn)之間。

5.4 總的來看,就是一個(gè)鏈表的插入結(jié)點(diǎn)過程,這個(gè)結(jié)點(diǎn)是以Message的when參數(shù)升序來進(jìn)行排序的。

6.Looper如何從MessageQueue取出Message對(duì)象

Looper.loop()方法循環(huán)地從MessageQueue中取出Message對(duì)象,查看源碼:

public static void loop() {//省略部分代碼for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}//省略部分代碼try {msg.target.dispatchMessage(msg);dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}//省略部分代碼}} 復(fù)制代碼

調(diào)用MessageQueue的next()方法,取出Message對(duì)象,如果為null,返回;如果不為null,調(diào)用msg.target.dispatchMessage(msg)分發(fā)消息(上面說到msg.target為發(fā)送該Message的Handler對(duì)象);

繼續(xù)查看MessageQueue的next方法源碼:

Message next() {//省略部分代碼for (;;) {//省略部分代碼synchronized (this) {// Try to retrieve the next message. Return if found.final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;if (msg != null) {if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// Got a message.mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}//省略部分代碼}}}復(fù)制代碼

6.1 首先獲取到當(dāng)前時(shí)間now,鏈表的頭節(jié)點(diǎn)mMessage賦值給msg;

6.2 如果now < msg.when,當(dāng)前時(shí)間小于Message的when參數(shù)(即sendMessageDelay的時(shí)候設(shè)置了延遲,或者sendMessageAtTime設(shè)置了未來時(shí)間),鏈表是按when排序的,頭節(jié)點(diǎn)都比now大,其他結(jié)點(diǎn)當(dāng)然更大,那么就計(jì)算出時(shí)間差,繼續(xù)執(zhí)行for循環(huán),直到now 大于等于msg.when,執(zhí)行mMessages = msg.next(頭節(jié)點(diǎn)設(shè)置為下一個(gè)結(jié)點(diǎn));msg.next = null, 然后返回msg,for循環(huán)結(jié)束(這里只分析了msg.target!=null的正常情況)

6.3 前面說過,sendMessageAtTime如果輸入的時(shí)間參數(shù)小于當(dāng)前時(shí)間,符合這里的now > msg.when條件,會(huì)直接返回msg,進(jìn)行分發(fā)處理。

7.Handler如何分發(fā)Message

繼續(xù)查看looper.loop方法,取出msg后,調(diào)用msg.target.dispatchMessage(msg),查看dispatchMessage方法的源碼:

public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}} 復(fù)制代碼

7.1 判斷msg.callback參數(shù)是否為空,即handler.post(runnable)中的Runable參數(shù),如果callback不為空,執(zhí)行Handler的handlerCallBack(msg)方法,交由Runnable對(duì)象callback去處理消息,調(diào)用callback的run方法。

private static void handleCallback(Message message) {message.callback.run();} 復(fù)制代碼

7.2 如果msg.callback為空,在判斷Handler的mCallBack方法是否為空,如果不為空的話(這個(gè)mCallBack,就是初始化Handler時(shí),傳入的Handler.CallBack類型的參數(shù),需要重寫handlerMessage方法),調(diào)用mCallBack的handlerMessage(msg)方法來處理。

7.3 如果msg.callback和Handler的mCallBack都為空的話,就去調(diào)用Handler的handlerMessage(msg)來處理。

轉(zhuǎn)載于:https://juejin.im/post/5bc44aff5188255c5644cccf

總結(jié)

以上是生活随笔為你收集整理的Handler消息处理机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。