最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

代碼分析Android消息機(jī)制

 更新時間:2018年03月18日 16:14:01   作者:mmmmar  
本文通過代碼實例詳細(xì)分析了Android消息機(jī)制的相關(guān)知識點,對此有需要的朋友可以參考學(xué)習(xí)下。

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

Handler的運(yùn)行主要由兩個類來支撐:Looper與MessageQueue。熟悉開發(fā)的朋友都知道在子線程中默認(rèn)是無法創(chuàng)建Handler的,這是因為子線程中不存在消息隊列。當(dāng)需要創(chuàng)建一個與子線程綁定的Handler時,標(biāo)準(zhǔn)代碼如下:

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

在創(chuàng)建Handler前,需要先調(diào)用Looper.prepare()方法,之后再調(diào)用Looper.loop()方法。也就是說Handler的功能實現(xiàn)建立在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的消息循環(huán)是一個死循環(huán),一個線程最多只能有一個Looper,所以Looper.prepare()函數(shù)首先檢查該線程是否已經(jīng)擁有一個Looper,如果有則拋出異常。Looper通過ThreadLocal類為每個線程儲存獨立的Looper實例,簡單說一下ThreadLocal的實現(xiàn)原理:

Java并發(fā)編程:深入剖析ThreadLocal

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

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

然后在當(dāng)前線程里面,如果要使用副本變量,就可以通過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與當(dāng)前線程相關(guān)聯(lián),也就無法進(jìn)行消息傳遞。Looper.loop()方法本身是一個死循環(huán),不斷在MessageQueue中取出Message對象進(jìn)行處理,然后調(diào)用Message.recycleUnchecked()方法對其回收,這也是為什么官方推薦使用Message.obtain()方法來獲取Message實例,而不是直接新建對象。當(dāng)沒有消息可處理時,MessageQueue.next()方法將阻塞,直到新的消息到來。

對于MessageQueue,我們只需要關(guān)注兩個函數(shù)即可,一個是MessageQueue.enqueueMessage()另一個是MessageQueue.next(),它們分別對應(yīng)著隊列的插入與取出操作。MessageQueue中隊列是使用單鏈表實現(xiàn)的,由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中插入元素時,需要根據(jù)Message.when屬性的大小決定插入的位置,它代表了Meesage需要被處理的時間,拿Handler.sendMessage()函數(shù)為例。

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

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

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

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()函數(shù)發(fā)送一個Runnable對象,那么最終Runnable對象會在Handler.handleCallback()函數(shù)中執(zhí)行。如果是一個普通Message,那么它會被分發(fā)到一個我們熟悉的函數(shù)中,Handler.handleMessage(),這就是為什么一般我們都需要重寫這個函數(shù)對消息進(jìn)行處理。

相關(guān)文章

  • Android 使用viewpager實現(xiàn)無限循環(huán)(定時+手動)

    Android 使用viewpager實現(xiàn)無限循環(huán)(定時+手動)

    這篇文章主要介紹了Android 使用viewpager實現(xiàn)無限循環(huán)(定時+手動)的相關(guān)資料,需要的朋友可以參考下
    2015-11-11
  • Android深入淺出之Binder機(jī)制

    Android深入淺出之Binder機(jī)制

    本文主要介紹 Android深入淺出之Binder機(jī)制,這里整理了詳細(xì)的Binder機(jī)制資料,研究Android源碼的朋友可以看下,以便了解Android 通信知識
    2016-08-08
  • Android使用ViewPager實現(xiàn)無限滑動效果

    Android使用ViewPager實現(xiàn)無限滑動效果

    相信在大家開發(fā)Android的時候,我們常常用ViewPager來為自己的應(yīng)用創(chuàng)建廣告條幅,并且常常會遇到ViewPager無限滑動這樣的需求。下面來一起看看吧。
    2016-09-09
  • Android實現(xiàn)登錄注冊功能

    Android實現(xiàn)登錄注冊功能

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)登錄注冊功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Android ListView自動顯示隱藏布局的實現(xiàn)方法

    Android ListView自動顯示隱藏布局的實現(xiàn)方法

    這篇文章主要介紹了Android ListView自動顯示隱藏布局的實現(xiàn)方法的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • android獲取屏幕的長與寬實現(xiàn)代碼(手寫)

    android獲取屏幕的長與寬實現(xiàn)代碼(手寫)

    android中獲取屏幕的長于寬,參考了網(wǎng)上有很多代碼,但結(jié)果與實際不符,如我的手機(jī)是i9000,屏幕大小是480*800px,得到的結(jié)果卻為320*533,于此問題很是疑惑,于是自己寫了幾行代碼,親測一下,效果還不錯,需要了解的朋友可以參考下
    2012-12-12
  • Android Jetpack 狠活Lifecycles與LiveData使用詳解

    Android Jetpack 狠活Lifecycles與LiveData使用詳解

    這篇文章主要為大家介紹了Android Jetpack 狠活Lifecycles與LiveData使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Android 關(guān)機(jī)彈出選擇菜單的深入解析

    Android 關(guān)機(jī)彈出選擇菜單的深入解析

    本篇文章是對Android 關(guān)機(jī)彈出選擇菜單進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Android實現(xiàn)隨意拖動View效果的實例代碼

    Android實現(xiàn)隨意拖動View效果的實例代碼

    這篇文章主要介紹了Android實現(xiàn)隨意拖動View效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • Android移除Message的方法分享

    Android移除Message的方法分享

    本篇文章主要介紹MessageQueue提供的各種移除Message的方法,大概有八九個,接下來會對其中比較典型的移除方法進(jìn)行詳細(xì)分析,需要的可以參考一下
    2022-10-10

最新評論

扎鲁特旗| 贺州市| 定西市| 顺平县| 绥中县| 宜兰县| 巴东县| 屏边| 盐源县| 白山市| 安图县| 石狮市| 大洼县| 泽库县| 正宁县| 南城县| 石阡县| 遵化市| 永昌县| 凤台县| 金塔县| 承德县| 九寨沟县| 天气| 新闻| 柳河县| 五华县| 冕宁县| 嘉祥县| 临高县| 依兰县| 岳普湖县| 临洮县| 沂水县| 鄯善县| 大埔区| 大冶市| 七台河市| 五原县| 广宁县| 武定县|