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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

小葵花妈妈课堂开课了:《Handler Looper Message 浅析》

發(fā)布時(shí)間:2023/12/18 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小葵花妈妈课堂开课了:《Handler Looper Message 浅析》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

# Handler Looper Message Thread

首先要闡述幾者之間的關(guān)系。 Thread 可以擁有多個(gè)handler對象; Thread 只能擁有一個(gè)Looper 和一個(gè)MessageQueue。

Looper 只能屬于一個(gè)Thread, 并且只能和MessageQueue 一一對應(yīng)。 looper的在幾者中的作用是什么呢! Looper的作用就是起到 發(fā)動(dòng)機(jī)的原理,當(dāng)然它不是讓車跑起來,而是讓MessageQueue里的message被執(zhí)行。 那么 Message被誰執(zhí)行呢? 后文即會提到。

MessageQueue 也僅是和一個(gè)looper綁定,在出生的時(shí)候即決定了這件事,后面在代碼中會解釋為什么! MessageQueue里面存放就是 Message。

Looper

首先需要關(guān)注的是該方法。

public static void prepare() {prepare(true); } 復(fù)制代碼

參數(shù)為是否允許退出,答案是肯定的 true; 只有一種情況即主線程調(diào)用prepare時(shí)傳遞false,因?yàn)橹骶€程不允許退出。 該方法即為 預(yù)熱發(fā)動(dòng)機(jī)的入口。讓 Looper這臺機(jī)器進(jìn)行啟動(dòng)之前的準(zhǔn)備工作。

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ù)制代碼

分析一下 是如何判斷已經(jīng)prepare的呢? sThreadLocal.get() != null 那就需要看一下set是什么東東。就是準(zhǔn)備的是什么呢?

/*** Sets the current thread's copy of this thread-local variable* to the specified value. Most subclasses will have no need to* override this method, relying solely on the {@link #initialValue}* method to set the values of thread-locals.** @param value the value to be stored in the current thread's copy of* this thread-local.*/ public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value); } 復(fù)制代碼

這個(gè)value就是上文提到的 new Looper(quitAllowed) createMap創(chuàng)建的是一個(gè)ThreadLocalMap。 每一個(gè)線程僅有一個(gè)ThreadLocalMap, 在該map中存儲內(nèi)容為該線程本地變量的副本。ThreadLocalMap使用及注意事項(xiàng)以后單獨(dú)開講。

void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue); } 復(fù)制代碼

當(dāng)?shù)谝淮蝧ThreadLocal.get()時(shí),會返回setInitialValue=null;

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

當(dāng)一個(gè)線程只能有一個(gè)Looper之后也就意味著只能有一個(gè)MessageQueue.class

Looper.loop即為啟動(dòng)發(fā)動(dòng)機(jī)的入口,啟動(dòng)之后開始進(jìn)行消息輪詢,并且注釋說明一定要調(diào)用quit()退出輪詢。 Looper一直把MesageQueue所有的message執(zhí)行完。 每執(zhí)行完一個(gè)后即通過next拿到下一個(gè)message.

public static void loop() { --- for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;} //當(dāng)隊(duì)列中沒有消息之后 即退出。// This must be in a local variable, in case a UI event sets the loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long traceTag = me.mTraceTag;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}try {msg.target.dispatchMessage(msg); //msg.target即為執(zhí)行message工具。} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}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();} } 復(fù)制代碼

MessageQueue MessageQueue和Looper之間有個(gè)緊密的聯(lián)系就是通過 MessageQueue.next()方法。以next方法為切入點(diǎn)介紹MessageQueue.class

Message next() {// Return here if the message loop has already quit and been disposed.// This can happen if the application tries to restart a looper after quit// which is not supported.final long ptr = mPtr;if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}//natvie層進(jìn)行阻塞,后文在Looper.c中介紹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;if (msg != null && msg.target == null) {// Stalled by a barrier. Find the next asynchronous message in the queue.// 當(dāng)因?yàn)橛?"同步分隔欄" 引起停滯后, 將要找到下一個(gè)異步消息, // 同步分隔欄后面的同步消息并不會執(zhí)行do {prevMsg = msg;msg = msg.next;} while (msg != null && !msg.isAsynchronous());}if (msg != null) {if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready.//如果當(dāng)前的msg沒有準(zhǔn)備好,那么就下次輪詢進(jìn)入到等待。//計(jì)算等待時(shí)間nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// Got a message.//標(biāo)記當(dāng)次輪詢不會被wait,不需要被喚醒mBlocked = false;//當(dāng)在鏈表隊(duì)列中找到可執(zhí)行msg,把當(dāng)前message調(diào)出,并修復(fù)原鏈接if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);//標(biāo)記當(dāng)前msg被使用狀態(tài)msg.markInUse();return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}// Process the quit message now that all pending messages have been handled.//如果looper調(diào)用了quit, messagequeue也進(jìn)行退出操作。if (mQuitting) {dispose();return null;}// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.// 引入了另外一個(gè)messagequeue的功能, idle handles的處理,// 當(dāng)隊(duì)列為空的時(shí)候或沒有任務(wù)可執(zhí)行的時(shí)候,執(zhí)行idle handles內(nèi)容。if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}if (pendingIdleHandlerCount <= 0) {// No idle handlers to run. Loop and wait some more.// 既沒有idle handlers 和message可以處理那么就需要阻塞,入隊(duì)時(shí)候就需要喚醒。mBlocked = true;continue;}if (mPendingIdleHandlers == null) {mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);}// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i = 0; i < pendingIdleHandlerCount; i++) {final IdleHandler idler = mPendingIdleHandlers[i];mPendingIdleHandlers[i] = null; // release the reference to the handlerboolean keep = false;try {//執(zhí)行idler中的回調(diào),并且有返回值,true意味著想要保持這個(gè)idle下次繼續(xù)執(zhí)行,//false則會從隊(duì)列中移除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;} } 復(fù)制代碼

下面繼續(xù)介紹enqueueMessage,入隊(duì)操作由Handler.class執(zhí)行。后文提到其中幾種入隊(duì)操作。

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) {//如果looper已經(jīng)條用quit,那么就放棄入隊(duì)。if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");Log.w(TAG, 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.// 如果messagequeue中沒有message或者需要立即執(zhí)行或者插入message時(shí)間優(yōu)于對頭// message所需要執(zhí)行時(shí)間,那么就把msg插入到對頭。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.//通常情況下將目標(biāo)message插入到隊(duì)里中間時(shí),是不需要喚醒隊(duì)列的,//除非有一個(gè)"同步分隔欄"在對頭或者目標(biāo)message是最早需要執(zhí)行的異步message。needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {//找到最后一個(gè)位置,或者時(shí)間排序上晚于目標(biāo)message的位置break;}//當(dāng)需要喚醒,但是 要插入目標(biāo)message的前面所有位置的message//只要有異步消息的話既不需要喚醒。if (needWake && p.isAsynchronous()) {needWake = false;}}// 將目標(biāo)message插入到理想位置,修復(fù)整個(gè)鏈接msg.next = p; // invariant: p == prev.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {//此處為喚醒 LoopernativeWake(mPtr);}}return true; } 復(fù)制代碼

上面介紹了MessageQueue的兩個(gè)主要方法next()和enqueueMessage(),其中涉及到了兩個(gè)native層的本地方法分別為: nativePollOnce(ptr, nextPollTimeoutMillis); nativeWake(mPtr); 那么下面介紹一下這兩個(gè)方法。 方法在/frameworks/base/core/jni/android_os_MessageQueue.cpp中進(jìn)行了定義。

static JNINativeMethod gMessageQueueMethods[] = {/* name, signature, funcPtr */{ "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },{ "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },{ "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },{ "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake } }; 復(fù)制代碼static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,jint ptr, jint timeoutMillis) {NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);nativeMessageQueue->pollOnce(timeoutMillis); } 復(fù)制代碼

最終調(diào)用到Looper::pollOnce====>Looper::pollInner

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); int Looper::pollInner(int timeoutMillis); 復(fù)制代碼int Looper::pollInner(int timeoutMillis) {--- #ifdef LOOPER_USES_EPOLLstruct epoll_event eventItems[EPOLL_MAX_EVENTS];//通過Epoll進(jìn)行阻塞int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); #else// Wait for wakeAndLock() waiters to run then set mPolling to true.mLock.lock();while (mWaiters != 0) {mResume.wait(mLock);}mPolling = true;mLock.unlock();size_t requestedCount = mRequestedFds.size();int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis); #endif--- }復(fù)制代碼

其中最終運(yùn)用epoll進(jìn)行控制(epoll不再本文討論感興趣讀者可自行查詢! )。下面引入《深入理解Android:卷II》對pollOnce解釋:

其中四個(gè)參數(shù): timeoutMillis參數(shù)為超時(shí)等待時(shí)間。如果值為–1,則表示無限等待,直到有事件發(fā)生為止。如果值為0,則無須等待立即返回。 outFd用來存儲發(fā)生事件的那個(gè)文件描述符。 outEvents用來存儲在該文件描述符上發(fā)生了哪些事件,目前支持可讀、可寫、錯(cuò)誤和中斷4個(gè)事件。這4個(gè)事件其實(shí)是從epoll事件轉(zhuǎn)化而來的。后面我們會介紹大名鼎鼎的epoll。 outData用于存儲上下文數(shù)據(jù),這個(gè)上下文數(shù)據(jù)是由用戶在添加監(jiān)聽句柄時(shí)傳遞的,它的作用和pthread_create函數(shù)最后一個(gè)參數(shù)param一樣,用來傳遞用戶自定義的數(shù)據(jù)。 另外,pollOnce函數(shù)的返回值也具有特殊的意義,具體如下: 當(dāng)返回值為ALOOPER_POLL_WAKE時(shí),表示這次返回是由wake函數(shù)觸發(fā)的,也就是管道寫端的那次寫事件觸發(fā)的。 返回值為ALOOPER_POLL_TIMEOUT表示等待超時(shí)。 返回值為ALOOPER_POLL_ERROR表示等待過程中發(fā)生錯(cuò)誤。 返回值為ALOOPER_POLL_CALLBACK表示某個(gè)被監(jiān)聽的句柄因某種原因被觸發(fā)。這時(shí),outFd參數(shù)用于存儲發(fā)生事件的文件句柄,outEvents用于存儲所發(fā)生的事件。

MessageQueue還有其他公開方法:

用來添加IdleHandler,當(dāng)沒有message需要立即處理時(shí)就會處理IdleHandler。

void addIdleHandler(@NonNull IdleHandler handler); void removeIdleHandler(@NonNull IdleHandler handler); 復(fù)制代碼

用來添加需要監(jiān)聽的文件描述符fd

void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,@OnFileDescriptorEventListener.Events int events,@NonNull OnFileDescriptorEventListener listener); void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd); 復(fù)制代碼

Message.class 主要是handler要處理的信使,主要功能攜帶參數(shù)。下面主要介紹handler參數(shù)。

/*** User-defined message code so that the recipient can identify * what this message is about. Each {@link Handler} has its own name-space* for message codes, so you do not need to worry about yours conflicting* with other handlers.*/ public int what; //定義在handler中要執(zhí)行的事件/*** arg1 and arg2 are lower-cost alternatives to using* {@link #setData(Bundle) setData()} if you only need to store a* few integer values.*/ public int arg1; //如果要存儲簡單的參數(shù),使用arg1和arg2就可以/*** arg1 and arg2 are lower-cost alternatives to using* {@link #setData(Bundle) setData()} if you only need to store a* few integer values.*/ public int arg2;/*** An arbitrary object to send to the recipient. When using* {@link Messenger} to send the message across processes this can only* be non-null if it contains a Parcelable of a framework class (not one* implemented by the application). For other data transfer use* {@link #setData}.* * <p>Note that Parcelable objects here are not supported prior to* the {@link android.os.Build.VERSION_CODES#FROYO} release.*/ public Object obj; //可存儲任意類型參數(shù)/*** Optional Messenger where replies to this message can be sent. The* semantics of exactly how this is used are up to the sender and* receiver.*/ public Messenger replyTo; //可實(shí)現(xiàn)跨進(jìn)程通信,后面會獨(dú)立章節(jié)進(jìn)行講解。/*** Optional field indicating the uid that sent the message. This is* only valid for messages posted by a {@link Messenger}; otherwise,* it will be -1.*/ public int sendingUid = -1; //與Messenger 配合使用/*package*/ int flags; //0x00 非使用, 0x01被使用:當(dāng)入隊(duì)和被回收的時(shí)候會設(shè)置為1 //0x10 表示為異步/*package*/ long when; //延遲執(zhí)行時(shí)間/*package*/ Bundle data; //存儲一些復(fù)雜數(shù)據(jù)/*package*/ Handler target; //執(zhí)行該message的handler/*package*/ Runnable callback; //hanlder執(zhí)行該message時(shí),如果有callback即執(zhí)行該callback// sometimes we store linked lists of these things /*package*/ Message next; //保存鏈表 復(fù)制代碼

主要解析一下該函數(shù)

/** * Return a new Message instance from the global pool. Allows us to* avoid allocating new objects in many cases.*/ public static Message obtain() {//sPoolSync 同步鎖synchronized (sPoolSync) {//sPool指向鏈表的頭if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;//將sPool取出,并斷鏈return m;}}//如果鏈中沒有元素,重新分配return new Message(); }/*** Recycles a Message that may be in-use.* Used internally by the MessageQueue and Looper when disposing of queued Messages.*/ 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 = -1;when = 0;target = null;callback = null;data = null;synchronized (sPoolSync) {//鏈表不會無限增長if (sPoolSize < MAX_POOL_SIZE) {next = sPool;sPool = this;sPoolSize++;//將該message插入頭部}} } 復(fù)制代碼

Handler 先比較前幾個(gè)Class, Handler比較簡單,成員只有以下幾個(gè):

final Looper mLooper; final MessageQueue mQueue; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; 復(fù)制代碼

先看幾個(gè)比較重要的構(gòu)造方法:

//常用的為無參構(gòu)造形式 public Handler() {this(null, false); }//這是無參構(gòu)造方法調(diào)用的真正構(gòu)造方法, public Handler(Callback callback, boolean async) {//FIND_POTENTIAL_LEAKS//將此標(biāo)志設(shè)置為true以檢測擴(kuò)展的Handler類, 擴(kuò)展的handler類如果不是靜態(tài)的匿名,本地或成員類, //則會產(chǎn)生泄漏。我們常見構(gòu)造時(shí)的警告說明!至于消除警告方法一般是設(shè)置成靜態(tài)或弱引用。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是來自于sThreadLocal中ThreadLocalMap中 通過調(diào)用線程ID存儲的looper,唯一mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}//mqueue來自looper, 也唯一mQueue = mLooper.mQueue;mCallback = callback;//標(biāo)示該handler發(fā)送的數(shù)據(jù)是否為異步數(shù)據(jù)。mAsynchronous = async; } 復(fù)制代碼

通過分析構(gòu)造方法可驗(yàn)證前文提到的 handler 僅對應(yīng)一個(gè)looper MessageQueue,,翻過來不成立,也就是說會有多個(gè)handler綁定在同一個(gè)Looper中。

通過調(diào)用post(Runnable r); postDelayed(Runnable r, long delayMillis);sendMessage(Message msg);等方法發(fā)送的時(shí)間,最終調(diào)用下面的方法。

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); }private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;//如果為異步,則對每一個(gè)message進(jìn)行設(shè)置。if (mAsynchronous) {msg.setAsynchronous(true);}//調(diào)用enqueueMessage 進(jìn)行入隊(duì)Messagereturn queue.enqueueMessage(msg, uptimeMillis); } 復(fù)制代碼

還有另外一種入隊(duì)方法,需要介紹:

public final boolean sendMessageAtFrontOfQueue(Message msg) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}//與enqueueMessage差別為uptimeMillis=0. 在messagequeue中當(dāng)遇到when=0時(shí),//會將該message放在對頭進(jìn)行處理return enqueueMessage(queue, msg, 0); } 復(fù)制代碼

在需要注意下,這個(gè)remove方法,當(dāng)傳入null時(shí)可將MessageQueue中的所有數(shù)據(jù)remove掉。

public final void removeCallbacksAndMessages(Object token) {mQueue.removeCallbacksAndMessages(this, token);} 復(fù)制代碼

回過頭來說一下上面的 同步分隔欄,

在Api 23 之, 通過MessageQueue 進(jìn)行調(diào)用

/*** Posts a synchronization barrier to the Looper's message queue.** Message processing occurs as usual until the message queue encounters the* synchronization barrier that has been posted. When the barrier is encountered,* later synchronous messages in the queue are stalled (prevented from being executed)* until the barrier is released by calling {@link #removeSyncBarrier} and specifying* the token that identifies the synchronization barrier.** This method is used to immediately postpone execution of all subsequently posted* synchronous messages until a condition is met that releases the barrier.* Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier* and continue to be processed as usual.** This call must be always matched by a call to {@link #removeSyncBarrier} with* the same token to ensure that the message queue resumes normal operation.* Otherwise the application will probably hang!** @return A token that uniquely identifies the barrier. This token must be* passed to {@link #removeSyncBarrier} to release the barrier.** @hide*/// 該方法為hide, 正常寫代碼是調(diào)用不到的。 public int postSyncBarrier() {return postSyncBarrier(SystemClock.uptimeMillis()); }// The next barrier token. // Barriers are indicated by messages with a null target whose arg1 field carries the token. // 同步分隔欄消息沒有target, 并且arg1用來記錄token private int mNextBarrierToken;private int postSyncBarrier(long when) {// Enqueue a new sync barrier token.// We don't need to wake the queue because the purpose of a barrier is to stall it.synchronized (this) {final int token = mNextBarrierToken++;final Message msg = Message.obtain();msg.markInUse();msg.when = when;msg.arg1 = token;Message prev = null;Message p = mMessages;if (when != 0) {while (p != null && p.when <= when) {prev = p;p = p.next;}}if (prev != null) { // invariant: p == prev.nextmsg.next = p;prev.next = msg;} else {msg.next = p;mMessages = msg;}return token;} } 復(fù)制代碼

這個(gè)同步分隔message有什么作用呢? 對開發(fā)者沒有明顯的提供,那么就是在系統(tǒng)及別使用。在ViewRootImpl.java中進(jìn)行了使用。

void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);if (!mUnbufferedInputDispatch) {scheduleConsumeBatchedInput();}notifyRendererOfFramePending();pokeDrawLockIfNeeded();} } 復(fù)制代碼

為了讓View能夠有快速的布局和繪制,ViewRootImpl在開始measure和layout ViewTree時(shí),會向主線程的Handler添加同步分隔message,這樣后續(xù)的消息隊(duì)列中的同步的消息將不會被執(zhí)行,以免會影響到UI繪制,但是只有異步消息才能被執(zhí)行。如果想要使用postSyncBarrier() 那么就需要使用反射進(jìn)行使用。

總結(jié) Looper、MessageQueue 和 Thread 一一對應(yīng)。 Handler 需要綁定到一個(gè)Looper中, 一個(gè)Looper可以有多個(gè)Handler。

這是第一文章,以后會多多寫的。歡迎各位指正問題!謝謝。 sy_dqs@163.com

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

總結(jié)

以上是生活随笔為你收集整理的小葵花妈妈课堂开课了:《Handler Looper Message 浅析》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 91成人免费看 | 久久久久亚洲AV成人 | 成人小视频在线看 | 伊人网色 | 手机免费av片 | 国产情侣一区二区 | 久久精品国产一区二区 | 香蕉视频国产在线观看 | 91久久精品日日躁夜夜躁欧美 | 狠狠躁天天躁夜夜躁婷婷 | 美女黄色一级片 | 日韩精品一区二 | 欧美人与物videos另类 | 催眠美妇肉奴系统 | 外国毛片 | 成人伊人 | 色玖玖综合 | 久草观看视频 | 色爱av综合 | 最近国语视频在线观看免费播放 | 国产精品无码专区 | 嘿咻视频在线观看 | 精品一区二区三区不卡 | 中文字幕人妻一区二 | 在线观看成人免费视频 | 中国丰满老太hd | 亚洲av成人无码久久精品老人 | 日本高清中文字幕 | 国产成人精品亚洲线观看 | 激情小说激情视频 | 欧美日本韩国一区 | 欧美在线一二三 | 日韩欧美精品一区二区三区 | 日韩tv | 久久久久久久久久久久久久免费看 | 亚洲天堂高清 | 尤物视频在线观看视频 | 欧美性xxxxx 亚洲特黄一级片 | 麻豆av在线免费观看 | 成人欧美视频在线观看 | 亚洲精品91在线 | 日韩资源网 | 久久无码视频一区 | 国产精品午夜视频 | 中文字幕永久在线播放 | 国产一区二区免费在线 | 国产精品美女www爽爽爽视频 | 久久人人妻人人人人妻性色av | 50部乳奶水在线播放 | 九色综合网 | 亚洲成人免费看 | 里番acg★同人里番本子大全 | 涩涩涩涩涩涩涩涩涩涩 | 中文日韩 | 丝袜 亚洲 另类 欧美 重口 | 国产午夜福利在线播放 | 亚洲精品一区二区三区四区乱码 | 国产精品啊啊啊 | 性高跟鞋xxxxhd国产电影 | 亚洲精品五月天 | 欧美一区二区三区爽爽爽 | 亚洲天堂一 | 欲求不满在线小早川怜子 | a级大片在线观看 | 日韩欧美黄色片 | 黄色小视频免费网站 | 国产美女在线精品 | 国产中文字幕在线观看 | 欧美热热 | 人妻丰满熟妇无码区免费 | 松本一香在线播放 | 天堂在线资源8 | 自拍偷自拍亚洲精品播放 | 另类第一页 | 亚洲视频图片 | 亚洲天天影视 | 欧美成人精品欧美一级乱黄 | 欧美一级性| 国产黄色一级网站 | 国产又黄又猛又粗 | 亚洲国产精品99 | yellow免费在线观看 | 青青91| 99re久久 | 999伊人 | 三级a视频 | 亚洲黄色精品 | 久久免费视屏 | 精品国产精品国产偷麻豆 | 一区二区三区四区视频在线观看 | 在线免费观看高清视频 | 黄色刺激视频 | 91香蕉一区二区三区在线观看 | 午夜时刻免费入口 | 日日操日日射 | av免费观看网 | 日本激情电影 | 伊人99| 奇米影视首页 |