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

首頁 > 系統 > Android > 正文

代碼分析Android消息機制

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

我們知道在編程時許多操作(如更新UI)需要在主線程中完成,而且,耗時操作(如網絡連接)需要放在子線程中,否則會引起ANR。所以我們常使用Handler來實現線程間的消息傳遞,這里討論的也就是Handler的運行機制。

Handler的運行主要由兩個類來支撐:Looper與MessageQueue。熟悉開發的朋友都知道在子線程中默認是無法創建Handler的,這是因為子線程中不存在消息隊列。當需要創建一個與子線程綁定的Handler時,標準代碼如下:

class LooperThread extends Thread {  public Handler mHandler;  public void run() {    Looper.prepare();    mHandler = new Handler() {      public void handleMessage(Message msg) {        // process incoming messages here      }    };    Looper.loop();   }}

在創建Handler前,需要先調用Looper.prepare()方法,之后再調用Looper.loop()方法。也就是說Handler的功能實現建立在Looper之上。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();final MessageQueue mQueue;final Thread mThread;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));}private Looper(boolean quitAllowed) {  mQueue = new MessageQueue(quitAllowed);  mThread = Thread.currentThread();}

由于Looper的消息循環是一個死循環,一個線程最多只能有一個Looper,所以Looper.prepare()函數首先檢查該線程是否已經擁有一個Looper,如果有則拋出異常。Looper通過ThreadLocal類為每個線程儲存獨立的Looper實例,簡單說一下ThreadLocal的實現原理:

Java并發編程:深入剖析ThreadLocal

首先,在每個線程Thread內部有一個ThreadLocal.ThreadLocalMap類型的成員變量threadLocals,這個threadLocals就是用來存儲實際的變量副本的,鍵值為當前ThreadLocal變量,value為變量副本。

初始時,在Thread里面,threadLocals為空,當通過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,并且以當前ThreadLocal變量為鍵值,以ThreadLocal要保存的副本變量為value,存到threadLocals。

然后在當前線程里面,如果要使用副本變量,就可以通過get方法在threadLocals里面查找。

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;  for (;;) {    Message msg = queue.next(); // might block    if (msg == null) {      // No message indicates that the message queue is quitting.      return;    }    msg.target.dispatchMessage(msg);    msg.recycleUnchecked();  }}

在4行可以看到一個我們熟悉的異常信息,說明并沒有Looper與當前線程相關聯,也就無法進行消息傳遞。Looper.loop()方法本身是一個死循環,不斷在MessageQueue中取出Message對象進行處理,然后調用Message.recycleUnchecked()方法對其回收,這也是為什么官方推薦使用Message.obtain()方法來獲取Message實例,而不是直接新建對象。當沒有消息可處理時,MessageQueue.next()方法將阻塞,直到新的消息到來。

對于MessageQueue,我們只需要關注兩個函數即可,一個是MessageQueue.enqueueMessage()另一個是MessageQueue.next(),它們分別對應著隊列的插入與取出操作。MessageQueue中隊列是使用單鏈表實現的,由Message.next屬性指向其下一個元素。

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) {      msg.next = p;      mMessages = msg;    } else {      Message prev;      for (;;) {        prev = p;        p = p.next;        if (p == null || when < p.when) {          break;        }      }      msg.next = p; // invariant: p == prev.next      prev.next = msg;    }  }  return true;}

向MessageQueue中插入元素時,需要根據Message.when屬性的大小決定插入的位置,它代表了Meesage需要被處理的時間,拿Handler.sendMessage()函數為例。

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

從調用流程來看,Handler.sendMessage()函數其實就是向MessageQueue的消息隊列中插入了一個Message.when屬性為當前時間的元素。

對于MessageQueue.next()函數,簡單來說它的作用就是在MessageQueue的頭部取出元素,然后執行Handler.dispatchMessage()函數。

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

如果我們使用Handler.post()函數發送一個Runnable對象,那么最終Runnable對象會在Handler.handleCallback()函數中執行。如果是一個普通Message,那么它會被分發到一個我們熟悉的函數中,Handler.handleMessage(),這就是為什么一般我們都需要重寫這個函數對消息進行處理。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 榕江县| 新闻| 深泽县| 华安县| 伊通| 高州市| 杂多县| 息烽县| 崇义县| 布拖县| 辉南县| 潼南县| 四川省| 陆丰市| 綦江县| 开原市| 鄂伦春自治旗| 大余县| 株洲市| 左云县| 田阳县| 巴林左旗| 神池县| 海口市| 定州市| 文安县| 宜兰市| 深州市| 托克逊县| 吉安县| 襄垣县| 延川县| 屯留县| 崇阳县| 新安县| 沧州市| 平顶山市| 朝阳县| 定安县| 富民县| 申扎县|