国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android消息循環機制源碼深入理解

2019-10-22 18:32:43
字體:
來源:轉載
供稿:網友

Android消息循環機制源碼

前言:

搞Android的不懂Handler消息循環機制,都不好意思說自己是Android工程師。面試的時候一般也都會問這個知識點,但是我相信大多數碼農肯定是沒有看過相關源碼的,頂多也就是網上搜搜,看看別人的文章介紹。學姐不想把那個萬能的關系圖拿出來討論。

近來找了一些關于android線程間通信的資料,整理學習了一下,并制作了一個簡單的例子。

 andriod提供了 Handler 和 Looper 來滿足線程間的通信。例如一個子線程從網絡上下載了一副圖片,當它下載完成后會發送消息給主線程,這個消息是通過綁定在主線程的Handler來傳遞的。

在Android,這里的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個事android的新 概念。我們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,我們引入一個新的機制Handle,我們有消息循環,就要往消息循環里 面發送相應的消息,自定義消息一般都會有自己對應的處理,消息的發送和清除,消息的的處理,把這些都封裝在Handle里面,注意Handle只是針對那 些有Looper的線程,不管是UI線程還是子線程,只要你有Looper,我就可以往你的消息隊列里面添加東西,并做相應的處理。
但是這里還有一點,就是只要是關于UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統等其他非UI的操作。

  在Android,這里的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個是android的新概念。我們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,我們引入一個新的機制Handler,我們有消息循環,就要往消息循環里面發送相應的消息,自定義消息一般都會有自己對應的處理,消息的發送和清除,把這些都封裝在Handler里面,注意Handler只是針對那 些有Looper的線程,不管是UI線程還是子線程,只要你有Looper,我就可以往你的消息隊列里面添加東西,并做相應的處理。

但是這里還有一點,就是只要是關于UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統等其他非UI的操作。

先從我們平時的使用方法引出這個機制,再結合源碼進行分析。

我們平時使用是這樣的:

 //1. 主線程 Handler handler = new MyHandler(); //2. 非主線程 HandlerThread handlerThread = new HandlerThread("handlerThread"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()); //發送消息 handler.sendMessage(msg); //接收消息 static class MyHandler extends Handler {  //對于非主線程處理消息需要傳Looper,主線程有默認的sMainLooper  public MyHandler(Looper looper) {   super(looper);  }  @Override  public void handleMessage(Message msg) {   super.handleMessage(msg);  } }

那么為什么初始化的時候,我們執行了1或2,后面只需要sendMessage就可處理任務了呢?學姐這里以非主線程為例進行介紹,handlerThread.start()的時候,實際上創建了一個用于消息循環的Looper和消息隊列MessageQueue,同時啟動了消息循環,并將這個循環傳給Handler,這個循環會從MessageQueue中依次取任務出來執行。用戶若要執行某項任務,只需要調用handler.sendMessage即可,這里做的事情是將消息添加到MessaeQueue中。對于主線程也類似,只是主線程sMainThread和sMainLooper不需要我們主動去創建,程序啟動的時候Application就創建好了,我們只需要創建Handler即可。

我們這里提到了幾個概念:

  • HandlerThread 支持消息循環的線程
  • Handler 消息處理器
  • Looper 消息循環對象
  • MessageQueue 消息隊列
  • Message 消息體

對應關系是:一對多,即(一個)HandlerThread、Looper、MessageQueue -> (多個)Handler、Message

源碼解析

1. Looper

(1)創建消息循環

prepare()用于創建Looper消息循環對象。Looper對象通過一個成員變量ThreadLocal進行保存。

(2)獲取消息循環對象

myLooper()用于獲取當前消息循環對象。Looper對象從成員變量ThreadLocal中獲取。

(3)開始消息循環

loop()開始消息循環。循環過程如下:

每次從消息隊列MessageQueue中取出一個Message

使用Message對應的Handler處理Message

已處理的Message加到本地消息池,循環復用

循環以上步驟,若沒有消息表明消息隊列停止,退出循環

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));}public static Looper myLooper() { return sThreadLocal.get();}public static void loop() { final Looper me = myLooper(); 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  Printer logging = me.mLogging;  if (logging != null) {   logging.println(">>>>> Dispatching to " + msg.target + " " +     msg.callback + ": " + msg.what);  }  msg.target.dispatchMessage(msg);  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(); }}

2. Handler

(1)發送消息

Handler支持2種消息類型,即Runnable和Message。因此發送消息提供了post(Runnable r)和sendMessage(Message msg)兩個方法。從下面源碼可以看出Runnable賦值給了Message的callback,最終也是封裝成Message對象對象。學姐個人認為外部調用不統一使用Message,應該是兼容Java的線程任務,學姐認為這種思想也可以借鑒到平常開發過程中。發送的消息都會入隊到MessageQueue隊列中。

(2)處理消息

Looper循環過程的時候,是通過dispatchMessage(Message msg)對消息進行處理。處理過程:先看是否是Runnable對象,如果是則調用handleCallback(msg)進行處理,最終調到Runnable.run()方法執行線程;如果不是Runnable對象,再看外部是否傳入了Callback處理機制,若有則使用外部Callback進行處理;若既不是Runnable對象也沒有外部Callback,則調用handleMessage(msg),這個也是我們開發過程中最常覆寫的方法了。

(3)移除消息

removeCallbacksAndMessages(),移除消息其實也是從MessageQueue中將Message對象移除掉。

public void handleMessage(Message msg) {}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();}public final Message obtainMessage(){ return Message.obtain(this);}public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0);}private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}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);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) {  msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token);}

3. MessageQueue

(1)消息入隊

消息入隊方法enqueueMessage(Message msg, long when)。其處理過程如下:

待入隊的Message標記為InUse,when賦值

若消息鏈表mMessages為空為空,或待入隊Message執行時間小于mMessage鏈表頭,則待入隊Message添加到鏈表頭

若不符合以上條件,則輪詢鏈表,根據when從低到高的順序,插入鏈表合適位置

(2)消息輪詢

next()依次從MessageQueue中取出Message

(3)移除消息

removeMessages()可以移除消息,做的事情實際上就是將消息從鏈表移除,同時將移除的消息添加到消息池,提供循環復用。

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) {  if (mQuitting) {   IllegalStateException e = new IllegalStateException(     msg.target + " sending message to a Handler on a dead thread");   Log.w("MessageQueue", 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.   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;}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 iteration int nextPollTimeoutMillis = 0; for (;;) {  if (nextPollTimeoutMillis != 0) {   Binder.flushPendingCommands();  }  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.    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.     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 (false) Log.v("MessageQueue", "Returning message: " + msg);     return msg;    }   } else {    // No more messages.    nextPollTimeoutMillis = -1;   }   // Process the quit message now that all pending messages have been handled.   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.   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);  }  // 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 handler   boolean keep = false;   try {    keep = idler.queueIdle();   } catch (Throwable t) {    Log.wtf("MessageQueue", "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; }}void removeMessages(Handler h, int what, Object object) { if (h == null) {  return; } synchronized (this) {  Message p = mMessages;  // Remove all messages at front.  while (p != null && p.target == h && p.what == what    && (object == null || p.obj == object)) {   Message n = p.next;   mMessages = n;   p.recycleUnchecked();   p = n;  }  // Remove all messages after front.  while (p != null) {   Message n = p.next;   if (n != null) {    if (n.target == h && n.what == what     && (object == null || n.obj == object)) {     Message nn = n.next;     n.recycleUnchecked();     p.next = nn;     continue;    }   }   p = n;  } }}

4. Message

(1)消息創建

Message.obtain()創建消息。若消息池鏈表sPool不為空,則從sPool中獲取第一個,flags標記為UnInUse,同時從sPool中移除,sPoolSize減1;若消息池鏈表sPool為空,則new Message()

(2)消息釋放

recycle()將消息釋放,從內部實現recycleUnchecked()可知,將flags標記為InUse,其他各種狀態清零,同時將Message添加到sPool,且sPoolSize加1

/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */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();}/** * Return a Message instance to the global pool. * <p> * You MUST NOT touch the Message after calling this function because it has * effectively been freed. It is an error to recycle a message that is currently * enqueued or that is in the process of being delivered to a Handler. * </p> */public void recycle() { if (isInUse()) {  if (gCheckRecycle) {   throw new IllegalStateException("This message cannot be recycled because it "     + "is still in use.");  }  return; } recycleUnchecked();}/** * 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++;  } }}

5. HandlerThread

由于Java中的Thread是沒有消息循環機制的,run()方法執行完,線程則結束。HandlerThread通過使用Looper實現了消息循環,只要不主動調用HandlerThread或Looper的quit()方法,循環就是一直走下去。

public class HandlerThread extends Thread {int mPriority;int mTid = -1;Looper mLooper;public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT;}@Overridepublic void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) {  mLooper = Looper.myLooper();  notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1;}public Looper getLooper() { if (!isAlive()) {  return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) {  while (isAlive() && mLooper == null) {   try {    wait();   } catch (InterruptedException e) {   }  } } return mLooper;}public boolean quit() { Looper looper = getLooper(); if (looper != null) {  looper.quit();  return true; } return false;}}

總結

  • 關鍵類:HandlerThread、Handler、Looper、MessageQueue、Messaga
  • MessageQueue數據結構,鏈表。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平南县| 灵山县| 南通市| 黄骅市| 安多县| 新巴尔虎左旗| 石河子市| 临猗县| 镇安县| 静海县| 蕲春县| 明光市| 建昌县| 绥德县| 腾冲县| 香格里拉县| 鄂尔多斯市| 登封市| 山阳县| 大理市| 井研县| 修武县| 怀远县| 阆中市| 东方市| 长兴县| 双辽市| 桃园县| 安康市| 长泰县| 鹤山市| 江达县| 台中县| 安龙县| 巩留县| 额敏县| 宜昌市| 翼城县| 泸西县| 厦门市| 于田县|