關(guān)于Android消息機(jī)制你所需要知道的細(xì)節(jié)

Android的消息機(jī)制幾乎是面試必問(wèn)的話題,當(dāng)然也并不是因?yàn)槊嬖?,而去學(xué)習(xí),更重要的是它在Android的開發(fā)中是必不可少的,占著舉足輕重的地位,所以弄懂它是很有必要的。下面就來(lái)說(shuō)說(shuō)最基本的東西。

Looper

作用:

  • 關(guān)聯(lián)起Thread
  • 循環(huán)取出消息

1、Looper是否可以直接實(shí)例化?

Looper構(gòu)造方法是私有的,其中做了兩件事

  • 創(chuàng)建一個(gè)MessageQueue
  • 得到與之對(duì)應(yīng)的Thread
 private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

2、一個(gè)線程能對(duì)應(yīng)多個(gè)Lopper?

不能,一個(gè)線程對(duì)應(yīng)一個(gè)Looper對(duì)象,通過(guò)ThreadLocal保證一個(gè)線程只有一個(gè)Looper與之對(duì)應(yīng),如果多次調(diào)用Looper.prepare();則會(huì)拋出運(yùn)行時(shí)異常。

 private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) { // 查看是否有l(wèi)ooper與當(dāng)前線程對(duì)應(yīng)
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

3、Looper是無(wú)限循環(huán),會(huì)阻塞嗎?

是,當(dāng)開啟一個(gè)loop后是一個(gè)死循環(huán),從MessageQueue中取出消息,處理消息,但是也有可能退出,在沒(méi)有消息后退出循環(huán)。

    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) { // 當(dāng)沒(méi)有消息的時(shí)候,退出
              // No message indicates that the message queue is quitting.
              return;
          }
        // 略
          msg.target.dispatchMessage(msg);
     }

4、可以再次調(diào)用Looper.prepareMainLooper嗎?

不可以,Looper.prepareMainLooper最終也是調(diào)用prepare(),同2.

public static void prepareMainLooper() {
    prepare(false); // 創(chuàng)建一個(gè)Looper
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been               prepared.");
        }
        sMainLooper = myLooper();
    }
}

5、MainLooper什么時(shí)候創(chuàng)建的?

MainLooper是啟動(dòng)Activity創(chuàng)建ActivityThread(并不是一個(gè)Thread)時(shí)候創(chuàng)建,所以不能多次創(chuàng)建。

public static void main(String[] args) {
  // 略
   Process.setArgV0("<pre-initialized>");
  Looper.prepareMainLooper();
  // 略
  ActivityThread thread = new ActivityThread();
  thread.attach(false);
  // 略
  if (sMainThreadHandler == null) {
    sMainThreadHandler = thread.getHandler();
  }

  // 略
  Looper.loop();
  throw new RuntimeException("Main thread loop unexpectedly exited");
  }
}

Handler

作用:

  • 發(fā)送消息到MessageQueue
  • 處理消息

1、Handler如何與Looper、MessageQueue關(guān)聯(lián)起來(lái)?

我們知道一個(gè)Looper對(duì)應(yīng)一個(gè)Thread,一個(gè)Looper包含一個(gè)MessageQueue。當(dāng)我們創(chuàng)建Handler時(shí)就會(huì)從當(dāng)前線程中取出與之對(duì)應(yīng)的Looper,讓后在從Looper中取出MessageQueue。

// 1、自動(dòng)獲取
public Handler(Callback callback, boolean async) {
    // 略
    mLooper = Looper.myLooper(); // 取出當(dāng)前線程中的Looper
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called                         Looper.prepare()");
    }
    mQueue = mLooper.mQueue; // 取出MessageQueue
    mCallback = callback;
    mAsynchronous = async;
}
// 2、傳遞一個(gè)Looper進(jìn)來(lái)
public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Message

單項(xiàng)鏈表結(jié)構(gòu)。

作用:

  • 數(shù)據(jù)的載體

1、消息如何復(fù)用的?

從全局消息池(鏈表結(jié)構(gòu))中

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

2、Message為什么能傳遞?

Android中想要傳遞對(duì)象要么實(shí)現(xiàn)Serializable要么Parcelable,在這里是實(shí)現(xiàn)了Parcelable接口。

public final class Message implements Parcelable {
  // 略
}

3、如何與Handler關(guān)聯(lián)?

我們知道在消息傳機(jī)制中Handler充當(dāng)著“快遞員”的角色,那么他又是如何與“貨物”--Message發(fā)生關(guān)系呢?實(shí)際上Message有一個(gè)成員變量target他的類型正是Handler,

/*package*/ Runnable callback;

public int arg1; 

public int arg2;

public Object obj;

/*package*/ Handler target; // 關(guān)鍵點(diǎn)

當(dāng)我們通過(guò)Handler去send一個(gè)Message時(shí)候最終都會(huì)為target賦值為this,即當(dāng)前的Handler。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 賦值語(yǔ)句
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

另為如果是通過(guò)Message.Obtain(),獲取的復(fù)用Message也會(huì)為其賦值。

多說(shuō)一句,Handler.obtainMessage()調(diào)用的就是Message.Obtain()。

public final Message obtainMessage(){
    return Message.obtain(this);
}

總結(jié):

通過(guò)一系列的包涵關(guān)系,最終Looper、Handler、Message、MessageQueue即發(fā)生關(guān)聯(lián),從而形成一個(gè)閉合,開啟消息循環(huán)。

困惑

最近一直在看這方面的知識(shí),但是能力有限,還是有不少困惑,如果有錯(cuò)誤,或你理解下面的問(wèn)題請(qǐng)聯(lián)系我fvaryu@qq.com,愿與君交流學(xué)習(xí),謝謝

1、Message中的sPool,哪里初始化的?為什么Message.obtain()中不會(huì)拋異常?

2、ActivityThread并不是線程,為什么可以創(chuàng)建一個(gè)Looper,Main Thread什么時(shí)候創(chuàng)建?

3、為什么序列化了的對(duì)象就可以傳遞?與Binder有關(guān)?

4、MessageQueue對(duì)應(yīng)的是NativeMessageQueue,具體實(shí)現(xiàn)需要學(xué)習(xí)?

5、Loop.loop(),會(huì)退出嗎?退出時(shí)機(jī)是什么?如果會(huì)退出,那么主線程同樣會(huì)退出嗎?
原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容