本篇內(nèi)容主要講解“Handler的原理有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Handler的原理有哪些”吧!
成都創(chuàng)新互聯(lián)公司主要從事網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)裕華,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
開頭需要建立個(gè)handler作用的總體印象,下面畫了一個(gè)總體的流程圖
從上面的流程圖可以看出,總體上是分幾個(gè)大塊的
Looper.prepare()、Handler()、Looper.loop() 總流程
收發(fā)消息
分發(fā)消息
相關(guān)知識(shí)點(diǎn)大概涉及到這些,下面詳細(xì)講解下!
需要詳細(xì)的查看該思維導(dǎo)圖,請(qǐng)右鍵下載后查看
先來看下使用,不然源碼,原理圖搞了一大堆,一時(shí)想不起怎么用的,就尷尬了
使用很簡(jiǎn)單,此處僅做個(gè)展示,大家可以熟悉下
演示代碼盡量簡(jiǎn)單是為了演示,關(guān)于靜態(tài)內(nèi)部類持有弱引用或者銷毀回調(diào)中清空消息隊(duì)列之類,就不在此處展示了
來看下消息處理的分發(fā)方法:dispatchMessage(msg)
Handler.java ... public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } ...
從上面源碼可知,handler的使用總的來說,分倆大類,細(xì)分三小類
收發(fā)消息一體
handleCallback(msg)
收發(fā)消息分開
mCallback.handleMessage(msg)
handleMessage(msg)
handleCallback(msg)
使用post形式,收發(fā)都是一體,都在post()方法中完成,此處不需要?jiǎng)?chuàng)建Message實(shí)例等,post方法已經(jīng)完成這些操作
public class MainActivity extends AppCompatActivity { private TextView msgTv; private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgTv = findViewById(R.id.tv_msg); //消息收發(fā)一體 new Thread(new Runnable() { @Override public void run() { String info = "第一種方式"; mHandler.post(new Runnable() { @Override public void run() { msgTv.setText(info); } }); } }).start(); } }
實(shí)現(xiàn)Callback接口
public class MainActivity extends AppCompatActivity { private TextView msgTv; private Handler mHandler = new Handler(new Handler.Callback() { //接收消息,刷新UI @Override public boolean handleMessage(@NonNull Message msg) { if (msg.what == 1) { msgTv.setText(msg.obj.toString()); } //false 重寫Handler類的handleMessage會(huì)被調(diào)用, true 不會(huì)被調(diào)用 return false; } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgTv = findViewById(R.id.tv_msg); //發(fā)送消息 new Thread(new Runnable() { @Override public void run() { Message message = Message.obtain(); message.what = 1; message.obj = "第二種方式 --- 1"; mHandler.sendMessage(message); } }).start(); } }
重寫Handler類的handlerMessage(msg)方法
public class MainActivity extends AppCompatActivity { private TextView msgTv; private Handler mHandler = new Handler() { //接收消息,刷新UI @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); if (msg.what == 1) { msgTv.setText(msg.obj.toString()); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgTv = findViewById(R.id.tv_msg); //發(fā)送消息 new Thread(new Runnable() { @Override public void run() { Message message = Message.obtain(); message.what = 1; message.obj = "第二種方式 --- 2"; mHandler.sendMessage(message); } }).start(); } }
大家肯定有印象,在子線程和子線程的通信中,就必須在子線程中初始化Handler,必須這樣寫
prepare在前,loop在后,固化印象了
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } });
為啥主線程不需要這樣寫,聰明你肯定想到了,在入口出肯定做了這樣的事
ActivityThread.java ... public static void main(String[] args) { ... //主線程Looper Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } //主線程的loop開始循環(huán) Looper.loop(); ... } ...
為什么要使用prepare和loop?我畫了個(gè)圖,先讓大家有個(gè)整體印象
上圖的流程,鄙人感覺整體畫的還是比較清楚的
總結(jié)下就是
Looper.prepare():生成Looper對(duì)象,set在ThreadLocal里
handler構(gòu)造函數(shù):通過Looper.myLooper()獲取到ThreadLocal的Looper對(duì)象
Looper.loop():內(nèi)部有個(gè)死循環(huán),開始事件分發(fā)了;這也是最復(fù)雜,干活最多的方法
具體看下每個(gè)步驟的源碼,這里也會(huì)標(biāo)定好鏈接,方便大家隨時(shí)過去查看
Looper.prepare()
可以看見,一個(gè)線程內(nèi),只能使用一次prepare(),不然會(huì)報(bào)異常的
Looper.java ... 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)); } ...
Handler()
這里通過Looper.myLooper() ---> sThreadLocal.get()拿到了Looper實(shí)例
Handler.java ... @Deprecated public Handler() { this(null, false); } public Handler(@Nullable Callback callback, boolean async) { 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 " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } ...
Looper.java ... public static @Nullable Looper myLooper() { return sThreadLocal.get(); } ...
Looper.loop():該方法分析,在分發(fā)消息
里講
精簡(jiǎn)了大量源碼,詳細(xì)的可以點(diǎn)擊上面方法名
Message msg = queue.next():遍歷消息
msg.target.dispatchMessage(msg):分發(fā)消息
msg.recycleUnchecked():消息回收,進(jìn)入消息池
Looper.java ... public static void loop() { final Looper me = myLooper(); ... final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... try { msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } .... msg.recycleUnchecked(); } } ...
收發(fā)消息的操作口都在Handler里,這是我們最直觀的接觸的點(diǎn)
下方的思維導(dǎo)圖整體做了個(gè)概括
在說發(fā)送和接受消息之前,必須要先解釋下,Message中一個(gè)很重要的屬性:when
when這個(gè)變量是Message中的,發(fā)送消息的時(shí)候,我們一般是不會(huì)設(shè)置這個(gè)屬性的,實(shí)際上也無法設(shè)置,只有內(nèi)部包才能訪問寫的操作;將消息加入到消息隊(duì)列的時(shí)候會(huì)給發(fā)送的消息設(shè)置該屬性。消息加入消息隊(duì)列方法:enqueueMessage(...)
在我們使用sendMessage發(fā)送消息的時(shí)候,實(shí)際上也會(huì)調(diào)用sendMessageDelayed延時(shí)發(fā)送消息發(fā)放,不過此時(shí)傳入的延時(shí)時(shí)間會(huì)默認(rèn)為0,來看下延時(shí)方法:sendMessageDelayed
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
這地方調(diào)用了sendMessageAtTime方法,此處!做了一個(gè)時(shí)間相加的操作:SystemClock.uptimeMillis() + delayMillis
SystemClock.uptimeMillis():這個(gè)方法會(huì)返回一個(gè)毫秒數(shù)值,返回的是,打開設(shè)備到此刻所消耗的毫秒時(shí)間,這很明顯是個(gè)相對(duì)時(shí)間刻!
delayMillis:就是我們發(fā)送的延時(shí)毫秒數(shù)值
后面會(huì)將這個(gè)時(shí)間刻賦值給when:when = SystemClock.uptimeMillis() + delayMillis
說明when代表的是開機(jī)到現(xiàn)在的一個(gè)時(shí)間刻,通俗的理解,when可以理解為:現(xiàn)實(shí)時(shí)間的某個(gè)現(xiàn)在或未來的時(shí)刻(實(shí)際上when是個(gè)相對(duì)時(shí)刻,相對(duì)點(diǎn)就是開機(jī)的時(shí)間點(diǎn))
發(fā)送消息涉及到倆個(gè)方法:post(...)和sendMessage(...)
post(Runnable):發(fā)送和接受消息都在post中完成
sendMessage(msg):需要自己傳入Message消息對(duì)象
看下源碼
此方法給msg的target賦值當(dāng)前handler之后,才進(jìn)行將消息添加的消息隊(duì)列的操作
msg.setAsynchronous(true):設(shè)置Message屬性為異步,默認(rèn)都為同步;設(shè)置為異步的條件,需要手動(dòng)在Handler構(gòu)造方法里面設(shè)置
使用post會(huì)自動(dòng)會(huì)通過getPostMessage方法創(chuàng)建Message對(duì)象
在enqueueMessage中將生成的Message加入消息隊(duì)列,注意
Handler.java ... //post public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } //生成Message對(duì)象 private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } //sendMessage方法 public final boolean sendMessage(@NonNull Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(@NonNull 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); } ///將Message加入詳細(xì)隊(duì)列 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { //設(shè)置target msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { //設(shè)置為異步方法 msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } ...
enqueueMessage(...):精簡(jiǎn)了一些代碼,完整代碼,可點(diǎn)擊左側(cè)方法名
A,B,C消息依次發(fā)送,三者分邊延時(shí):3秒,1秒,2秒 { A(3000)、B(1000)、C(2000) }
這是一種理想情況:三者依次進(jìn)入,進(jìn)入之間的時(shí)間差小到忽略,這是為了方便演示和說明
這種按照時(shí)間遠(yuǎn)近的循序排列,可以保證未延時(shí)或者延時(shí)時(shí)間較小的消息,能夠被及時(shí)執(zhí)行
在消息隊(duì)列中的排列為:B ---> C ---> A
mMessage為空,傳入的msg則為消息鏈表頭,next置空
mMessage不為空、消息隊(duì)列中沒有延時(shí)消息的情況:從當(dāng)前分發(fā)位置移到鏈表尾,將傳入的msg插到鏈表尾部,next置空
Message通過enqueueMessage加入消息隊(duì)列
請(qǐng)明確:when = SystemClock.uptimeMillis() + delayMillis,when代表的是一個(gè)時(shí)間刻度,消息進(jìn)入到消息隊(duì)列,是按照時(shí)間刻度排列的,時(shí)間刻度按照從小到大排列,也就是說消息在消息隊(duì)列中:按照從現(xiàn)在到未來的循序排隊(duì)
這地方有幾種情況,記錄下:mMessage為當(dāng)前消息分發(fā)到的消息位置
mMessage不為空、含有延時(shí)消息的情況:舉個(gè)例子
MessageQueue.java ... 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 { // 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; } ...
來看下發(fā)送的消息插入消息隊(duì)列的圖示
接受消息相對(duì)而言就簡(jiǎn)單多
dispatchMessage(msg):關(guān)鍵方法呀
Handler.java ... public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } ...
handleCallback(msg)
觸發(fā)條件:Message消息中實(shí)現(xiàn)了handleCallback回調(diào)
現(xiàn)在基本上只能使用post()方法了,setCallback(Runnable r) 被表明為@UnsupportedAppUsage,被hide了,沒法調(diào)用,如果使用反射倒是可以調(diào)用,但是沒必要。。。
mCallback.handleMessage(msg)
使用sendMessage方法發(fā)送消息(必須)
實(shí)現(xiàn)Handler的Callback回調(diào)
觸發(fā)條件
分發(fā)的消息,會(huì)在Handler中實(shí)現(xiàn)的回調(diào)中分發(fā)
handleMessage(msg)
使用sendMessage方法發(fā)送消息(必須)
未實(shí)現(xiàn)Handler的Callback回調(diào)
實(shí)現(xiàn)了Handler的Callback回調(diào),返回值為false(mCallback.handleMessage(msg))
觸發(fā)條件
需要重寫Handler類的handlerMessage方法
消息分發(fā)是在loop()中完成的,來看看loop()這個(gè)重要的方法
Looper.loop():精簡(jiǎn)了巨量源碼,詳細(xì)的可以點(diǎn)擊左側(cè)方法名
Message msg = queue.next():遍歷消息
msg.target.dispatchMessage(msg):分發(fā)消息
msg.recycleUnchecked():消息回收,進(jìn)入消息池
Looper.java ... public static void loop() { final Looper me = myLooper(); ... final MessageQueue queue = me.mQueue; ... for (;;) { //遍歷消息池,獲取下一可用消息 Message msg = queue.next(); // might block ... try { //分發(fā)消息 msg.target.dispatchMessage(msg); ... } catch (Exception exception) { ... } finally { ... } .... //回收消息,進(jìn)圖消息池 msg.recycleUnchecked(); } } ...
遍歷消息的關(guān)鍵方法肯定是下面這個(gè)
Message msg = queue.next():Message類中的next()方法;當(dāng)然這必須要配合外層for(無限循環(huán))來使用,才能遍歷消息隊(duì)列
來看看這個(gè)Message中的next()方法吧
next():精簡(jiǎn)了一些源碼,完整的點(diǎn)擊左側(cè)方法名
MessageQueue.java ... Message next() { final long ptr = mPtr; ... int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { ... //阻塞,除非到了超時(shí)時(shí)間或者喚醒 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; // 這是關(guān)于同步屏障(SyncBarrier)的知識(shí),放在同步屏障欄目講 if (msg != null && msg.target == null) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { //每個(gè)消息處理有耗時(shí)時(shí)間,之間存在一個(gè)時(shí)間間隔(when是將要執(zhí)行的時(shí)間點(diǎn))。 //如果當(dāng)前時(shí)刻還沒到執(zhí)行時(shí)刻(when),計(jì)算時(shí)間差值,傳入nativePollOnce定義喚醒阻塞的時(shí)間 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false; //該操作是把異步消息單獨(dú)從消息隊(duì)列里面提出來,然后返回,返回之后,該異步消息就從消息隊(duì)列里面剔除了 //mMessage仍處于未分發(fā)的同步消息位置 if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); //返回符合條件的Message return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } //這是處理調(diào)用IdleHandler的操作,有幾個(gè)條件 //1、當(dāng)前消息隊(duì)列為空(mMessages == null) //2、已經(jīng)到了可以分發(fā)下一消息的時(shí)刻(now < mMessages.when) if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
總結(jié)下源碼里面表達(dá)的意思
next()內(nèi)部是個(gè)死循環(huán),你可能會(huì)疑惑,只是拿下一節(jié)點(diǎn)的消息,為啥要死循環(huán)?
為了執(zhí)行延時(shí)消息以及同步屏障等等,這個(gè)死循環(huán)是必要的
nativePollOnce阻塞方法:到了超時(shí)時(shí)間(nextPollTimeoutMillis)或者通過喚醒方式(nativeWake),會(huì)解除阻塞狀態(tài)
nextPollTimeoutMillis大于等于零,會(huì)規(guī)定在此段時(shí)間內(nèi)休眠,然后喚醒
消息隊(duì)列為空時(shí),nextPollTimeoutMillis為-1,進(jìn)入阻塞;重新有消息進(jìn)入隊(duì)列,插入頭結(jié)點(diǎn)的時(shí)候會(huì)觸發(fā)nativeWake喚醒方法
如果 msg.target == null為零,會(huì)進(jìn)入同步屏障狀態(tài)
會(huì)將msg消息死循環(huán)到末尾節(jié)點(diǎn),除非碰到異步方法
如果碰到同步屏障消息,理論上會(huì)一直死循環(huán)上面操作,并不會(huì)返回消息,除非,同步屏障消息被移除消息隊(duì)列
當(dāng)前時(shí)刻和返回消息的when判定
消息when代表的時(shí)刻:一般都是發(fā)送消息的時(shí)刻,如果是延時(shí)消息,就是 發(fā)送時(shí)刻+延時(shí)時(shí)間
當(dāng)前時(shí)刻小于返回消息的when:進(jìn)入阻塞,計(jì)算時(shí)間差,給nativePollOnce設(shè)置超時(shí)時(shí)間,超時(shí)時(shí)間一到,解除阻塞,重新循環(huán)取消息
當(dāng)前時(shí)刻大于返回消息的when:獲取可用消息返回
消息返回后,會(huì)將mMessage賦值為返回消息的下一節(jié)點(diǎn)(只針對(duì)不涉及同步屏障的同步消息)
這里簡(jiǎn)單的畫了個(gè)流程圖
分發(fā)消息主要的代碼是: msg.target.dispatchMessage(msg);
也就是說這是Handler類中的dispatchMessage(msg)方法
dispatchMessage(msg)
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
可以看到,這里的代碼,在收發(fā)消息欄目的接受消息那塊已經(jīng)說明過了,這里就無須重復(fù)了
msg.recycleUnchecked()是處理完成分發(fā)的消息,完成分發(fā)的消息并不會(huì)被回收掉,而是會(huì)進(jìn)入消息池,等待被復(fù)用
recycleUnchecked():回收消息的代碼還是蠻簡(jiǎn)單的,來分析下
默認(rèn)最大容量為50: MAX_POOL_SIZE = 50
首先會(huì)將當(dāng)前已經(jīng)分發(fā)處理的消息,相關(guān)屬性全部重置,flags也標(biāo)志可用
消息池的頭結(jié)點(diǎn)會(huì)賦值為當(dāng)前回收消息的下一節(jié)點(diǎn),當(dāng)前消息成為消息池頭結(jié)點(diǎn)
簡(jiǎn)言之:回收消息插入消息池,當(dāng)做頭結(jié)點(diǎn)
需要注意的是:消息池有最大的容量,如果消息池大于等于默認(rèn)設(shè)置的最大容量,將不再接受回收消息入池
Message.java ... void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
來看下消息池回收消息圖示
既然有將已使用的消息回收到消息池的操作,那肯定有獲取消息池里面消息的方法了
obtain():代碼很少,來看看
如果消息池不為空:直接取消息池的頭結(jié)點(diǎn),被取走頭結(jié)點(diǎn)的下一節(jié)點(diǎn)成為消息池的頭結(jié)點(diǎn)
如果消息池為空:直接返回新的Message實(shí)例
Message.java ... public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
來看下從消息池取一個(gè)消息的圖示
在MessageQueue類中的next方法里,可以發(fā)現(xiàn)有關(guān)于對(duì)IdleHandler的處理,大家可千萬別以為它是什么Handler特殊形式之類,這玩意就是一個(gè)interface,里面抽象了一個(gè)方法,結(jié)構(gòu)非常的簡(jiǎn)單
next():精簡(jiǎn)了大量源碼,只保留IdleHandler處理的相關(guān)邏輯;完整的點(diǎn)擊左側(cè)方法名
MessageQueue.java ... Message next() { final long ptr = mPtr; ... int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { ... //阻塞,除非到了超時(shí)時(shí)間或者喚醒 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; ... //這是處理調(diào)用IdleHandler的操作,有幾個(gè)條件 //1、當(dāng)前消息隊(duì)列為空(mMessages == null) //2、未到到了可以分發(fā)下一消息的時(shí)刻(now < mMessages.when) //3、pendingIdleHandlerCount < 0表明:只會(huì)在此for循環(huán)里執(zhí)行一次處理IdleHandler操作 if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } pendingIdleHandlerCount = 0; nextPollTimeoutMillis = 0; } }
實(shí)際上從上面的代碼里面,可以分析出很多信息
IdleHandler相關(guān)信息
調(diào)用條件
當(dāng)前消息隊(duì)列為空(mMessages == null) 或 未到分發(fā)返回消息的時(shí)刻
在每次獲取可用消息的死循環(huán)中,IdleHandler只會(huì)被處理一次:處理一次后pendingIdleHandlerCount為0,其循環(huán)不可再被執(zhí)行
實(shí)現(xiàn)了IdleHandler中的queueIdle方法
返回false,執(zhí)行后,IdleHandler將會(huì)從IdleHandler列表中移除,只能執(zhí)行一次:默認(rèn)false
返回true,每次分發(fā)返回消息的時(shí)候,都有機(jī)會(huì)被執(zhí)行:處于?;?/code>狀態(tài)
IdleHandler代碼
MessageQueue.java ... /** * Callback interface for discovering when a thread is going to block * waiting for more messages. */ public static interface IdleHandler { /** * Called when the message queue has run out of messages and will now * wait for more. Return true to keep your idle handler active, false * to have it removed. This may be called if there are still messages * pending in the queue, but they are all scheduled to be dispatched * after the current time. */ boolean queueIdle(); } public void addIdleHandler(@NonNull IdleHandler handler) { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } synchronized (this) { mIdleHandlers.add(handler); } } public void removeIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } }
怎么使用IdleHandler呢?
public class MainActivity extends AppCompatActivity { private TextView msgTv; private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgTv = findViewById(R.id.tv_msg); //添加IdleHandler實(shí)現(xiàn)類 mHandler.getLooper().getQueue().addIdleHandler(new InfoIdleHandler("我是IdleHandler")); mHandler.getLooper().getQueue().addIdleHandler(new InfoIdleHandler("我是大帥比")); //消息收發(fā)一體 new Thread(new Runnable() { @Override public void run() { String info = "第一種方式"; mHandler.post(new Runnable() { @Override public void run() { msgTv.setText(info); } }); } }).start(); } //實(shí)現(xiàn)IdleHandler類 class InfoIdleHandler implements MessageQueue.IdleHandler { private String msg; InfoIdleHandler(String msg) { this.msg = msg; } @Override public boolean queueIdle() { msgTv.setText(msg); return false; } } }
這里簡(jiǎn)單寫下用法,可以看看,留個(gè)印象
通俗的講:當(dāng)所有消息處理完了 或者 你發(fā)送了延遲消息,在這倆種空閑時(shí)間里,都滿足執(zhí)行IdleHandler的條件
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、服務(wù)器托管、標(biāo)簽優(yōu)化、定制網(wǎng)站、手機(jī)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)