亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何進行Handler、Looper與MessageQueue源碼分析

發布時間:2022-01-12 11:31:40 來源:億速云 閱讀:136 作者:柒染 欄目:移動開發

本篇文章為大家展示了如何進行Handler、Looper與MessageQueue源碼分析,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

在Android中可以通過Handler來更新主線程中UI的變化,更新UI只能在主線程中進行更新,而為了讓其他線程也能控制UI的變化,Android提供了一種機制Handler、Looper與MessageQueue一同協作來達到其他線程更新UI的目的。

一般我們會在主線程中通過如下方法定義一個Handler

private Handler mHandler = new Handler() {         @Override         public void handleMessage(Message msg) {             tv.setText("mHandler change UI");             super.handleMessage(msg);         }     };

一般都見不到Looper與MessageQueue的,那么它們都是在哪里調用與如何協作的呢?在主線程不會顯式的調用Looper而是會在ActivityThread.main方法中默認調用。

public static void main(String[] args) {          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");         SamplingProfilerIntegration.start();           // CloseGuard defaults to true and can be quite spammy.  We         // disable it here, but selectively enable it later (via         // StrictMode) on debug builds, but using DropBox, not logs.         CloseGuard.setEnabled(false);           Environment.initForCurrentUser();           // Set the reporter for event logging in libcore         EventLogger.setReporter(new EventLoggingReporter());           // Make sure TrustedCertificateStore looks in the right place for CA certificates         final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());          TrustedCertificateStore.setDefaultUserDirectory(configDir);           Process.setArgV0("<pre-initialized>");           Looper.prepareMainLooper();//創建Looper           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();//開啟Looper循環           throw new RuntimeException("Main thread loop unexpectedly exited");     }

如上代碼,調用了Looper.prepareMainLooper()方法,在主線程中創建了一個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));//創建Looper并賦給sThreadLocal     }       /**      * Initialize the current thread as a looper, marking it as an      * application's main looper. The main looper for your application      * is created by the Android environment, so you should never need      * to call this function yourself.  See also: {@link #prepare()}      */     public static void prepareMainLooper() {         prepare(false);         synchronized (Looper.class) {             if (sMainLooper != null) {                 throw new IllegalStateException("The main Looper has already been prepared.");             }             sMainLooper = myLooper();         }     }           public static @Nullable Looper myLooper() {         return sThreadLocal.get();     }

在prepareMainLooper方法中調用了prepare而通過prepare會發現它其實就是創建了一個Looper,并把它賦給了sThreadLocal。同時可以通過myLooper方法獲取當前線程中的Looper。再來看下new  Looper(quitAllowed)初始化了什么

private Looper(boolean quitAllowed) {         mQueue = new MessageQueue(quitAllowed);         mThread = Thread.currentThread();     }

在這里我們終于看到了MessageQueue了,它創建了一個MessageQueue。該消息隊列就是用來保存后續的Message。再回到ActivityThread.main方法中,發現它調用了Looper.loop()是用來開啟Looper循環的,監聽消息隊列MessageQueue中的消息。

loop

我們來看下Looper.loop()的源碼:

public static void loop() {         final Looper me = myLooper();//獲取Looper         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             final 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.traceBegin(traceTag, msg.target.getTraceName(msg));             }             try {                 msg.target.dispatchMessage(msg);//通過Handler分發消息             } 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();         }     }

在loop中首先獲取了當前所在線程的Looper,同時也獲取到了Looper中的MessageQueue,說明Looper已經與當前的線程進行了綁定。在后面開啟了一個for的死循環,發現它做的事件是不斷的從消息隊列中取出消息,***都交給msg.target調用它的dispatchMessage方法,那么target又是什么呢?我們進入Message

Message

/*package*/ int flags;      /*package*/ long when;          /*package*/ Bundle data;          /*package*/ Handler target;          /*package*/ Runnable callback;          // sometimes we store linked lists of these things     /*package*/ Message next;

發現它就是我們熟悉的Handler,說明***調用的就是Handler中的dispatchMessage方法,對消息的分發處理。這樣一來Handler就通過Looper聯系上了Looper所綁定的線程,即為主線程。

Handler

public Handler(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 that has not called Looper.prepare()");         }         mQueue = mLooper.mQueue;         mCallback = callback;         mAsynchronous = async;     }

通過Handler的初始化,它獲取了它所處線程的Looper,同時也獲取了Looper中的消息隊列。當然如果所處線程的Looper為空的話就會拋出異常,這就解釋了為什么在非主線程中創建Handler要分別調用Looper.prepare與Looper.loop而主線程則不需要,因為它默認已經調用了。

dispatchMessage

public void dispatchMessage(Message msg) {         if (msg.callback != null) {             handleCallback(msg);         } else {             if (mCallback != null) {                 if (mCallback.handleMessage(msg)) {                     return;                 }             }             handleMessage(msg);         }     } private static void handleCallback(Message message) {         message.callback.run();     }

回到前面,對于dispatchMessage的處理,首先判斷msg.callback是否為空,這里callback通過上面的Message應該能知道他就是一個Runnable,如果不為空則直接調用Runnable的run方法。否則調用Handler的handleMessage方法.而這個方法相信大家已經很熟悉了,對事件的處理都是在這個方法中執行的。因為通過前面我們已經知道了Handler已經聯系上了主線程,所以handleMessage中的處理自然相對于在主線程中進行,自然也能更新UI了。通過這里我們能把Looper比作是一個橋梁,來連接Looper所在的線程與Handler之間的通信,同時管理消息隊列MessageQueue中的消息。那么前面的Runnable又是如何不為空的呢?我們使用Handler有兩種方法,一種是直接創建一個Handler并且重寫它的handleMessage方法,而另一種可以通過Handler.post(Runnable)來使用,這樣事件的處理自然就在run方法中實現。

上面介紹了Handler是如何聯系上了需要操作的線程與對消息是如何取出與處理的。下面來談談消息是如何放入到Looper中的MessageQueue中的。

sendMessageAtTime

通過Handler發送消息的方式很多,例如:sendMessage、sendEmptyMessage與sendMessageDelayed等,其實到***他們調用的都是sendMessageAtTime方法。所以還是來看下sendMessageAtTime方法中的實現。

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);     }

而sendMessageAtTime則就是調用了enqueueMessage操作,看這方法名就知道是入隊列操作了。

enqueueMessage

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

果不其然直接調用了MessageQueue中的queue.enqueueMessage(msg,  uptimeMillis)將消息加入消息隊列,同時這段代碼msg.target = this  將當前的Handler賦給了msg.target,這就是前面所說的Looper.loop方法中調用的Handler。這樣就把消息放到了MessageQueue中,進而通過前面所講的loop來取出消息進行相應的處理,這樣就構成了整個對消息進行處理的系統。這也是使用Handler內部所發生的原理。好了Handler、Looper與MessageQueue它們之間的聯系基本就是這些了。我也簡單畫了張圖希望有所幫助

如何進行Handler、Looper與MessageQueue源碼分析

上述內容就是如何進行Handler、Looper與MessageQueue源碼分析,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沾益县| 临颍县| 岫岩| 马山县| 云梦县| 邓州市| 辉南县| 东丰县| 西和县| 勐海县| 永安市| 独山县| 聊城市| 荣成市| 航空| 徐闻县| 兴隆县| 武宣县| 喀喇沁旗| 蓬溪县| 台东县| 金山区| 通许县| 会东县| 丰宁| 平谷区| 页游| 富宁县| 梓潼县| 蕉岭县| 驻马店市| 大悟县| 柳河县| 阿拉善左旗| 福清市| 丰城市| 临城县| 甘泉县| 仪征市| 林周县| 兰溪市|