Android消息機制源碼分析

本篇主要介紹Android中的消息機制,即Looper、Handler是如何協同工做的;oop

Looper:主要用來管理當前線程的消息隊列,每一個線程只能有一個Looperpost

Handler:用來將消息(Message)插入到當前線程的消息隊列,並負責分發Looper中的消息,將消息發送到當前線程執行ui

具體關係圖以下所示:this

接下來咱們來分析一下Looper和Handler的源碼,瞭解一下其中的奧妙。spa

首先咱們從一個程序運行的入口來分析,源碼以下:線程

public static void main(String[] args){
    
    ......
    Looper.prepareMainLooper();//初始化Looper
    
    ......
    if(smainThreadHandler==null){
    smainThreadHandler=thread.getHandler();//初始化Handler
    }
    
    ......
    
    Looper.loop();//消息循環執行
    }

能夠看出,程序在運行的時候首先會建立主線程的Looper對象,並經過Looper開啓消息循環,不停的取出消息並執行;code

接下來咱們來研究Looper的源碼;對象

第一部分:Looper源碼blog

初始化接口

 1  private Looper(boolean quitAllowed) {
 2         mQueue = new MessageQueue(quitAllowed);
 3         mThread = Thread.currentThread();
 4     }
 5     
 6     初始化Looper對象(該過程包含初始化消息隊列和當前線程對象)
 7     private static void prepare(boolean quitAllowed) {
 8         if (sThreadLocal.get() != null) {
 9             throw new RuntimeException("Only one Looper may be created per thread");
10         }
11         sThreadLocal.set(new Looper(quitAllowed));
12     }

能夠看出Looper在初始化的時候,首先會建立消息隊列,並經過sThreadLocal保存在當前的線程本地變量中;

再來看一下程序入口Looper.prepareMainLooper();//初始化Looper究竟執行了什麼

 1 //初始化主線程的Looper對象
 2      public static void prepareMainLooper() {
 3         prepare(false);
 4         synchronized (Looper.class) {
 5             if (sMainLooper != null) {
 6                 throw new IllegalStateException("The main Looper has already been prepared.");
 7             }
 8             sMainLooper = myLooper();
 9         }
10     }

這裏有兩行關鍵的代碼:prepare(false);和sMainLooper = myLooper();

首先咱們來看prepare(false);即上面講到的 初始化Looper,能夠看看上面的源碼;

咱們來看sMainLooper = myLooper();

 

1  public static @Nullable Looper myLooper() {
2         return sThreadLocal.get();
3     }

 

很是簡單,咱們上面提到在初始化Looper的時候會把Looper保存到當前線程的本地變量中,而這行代碼的意思

就是從線程本地變量中將looper取出來

有了Looper,程序怎樣才能運行?答案就在Looper.loop();//消息循環執行

 1  public static void loop() {
 2         final Looper me = myLooper();//獲得當前線程的Looper對象
 3         if (me == null) {
 4             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
 5         }
 6         final MessageQueue queue = me.mQueue;//獲得消息隊列
 7 
 8       ......
 9 
10       //執行消息循環
11         for (;;) {
12             Message msg = queue.next(); // might block
13             if (msg == null) {
14                 // No message indicates that the message queue is quitting.
15                 return;
16             }
17             msg.target.dispatchMessage(msg);
18             msg.recycleUnchecked();
19         }
20     }

顯而易見,loop方法就是獲取到當前線程的Looper對象,並從中循環取出消息,並執行,程序就這樣跑起來了,具體是如何分發消息的

咱們將會在下面講解;

 

至此咱們至少應該明白,當主線程在執行的時候

一、初始化Looper,並將Looper保存的線程變量中

二、Looper在初始化的時候會建立消息隊列,並管理消息隊列

二、取出Looper,並從消息隊列中取出消息,循環執行

 

第二部分:Handler源碼

 

咱們知道Handler有兩種使用方式,一種是使用handler.post(Runnable r);另外一種是複寫handleMessage(Message msg)方法

複寫handleMessage(Message msg)方法很是簡單,Handler在消息分發的時候,直接回調該方法便可,咱們主要來研究第一種

 

1 public final boolean post(Runnable r)
2     {
3        return  sendMessageDelayed(getPostMessage(r), 0);
4     }

 

看到這個咱們首先得明白getPostMessage(r)幹了什麼

 

 

1 private static Message getPostMessage(Runnable r) {
2         Message m = Message.obtain();
3         m.callback = r;
4         return m;
5     }

 

能夠看出是將r封裝成了一個消息,r做爲該消息的回調;

咱們接着看:

1 public final boolean sendMessageDelayed(Message msg, long delayMillis)
2     {
3         if (delayMillis < 0) {
4             delayMillis = 0;
5         }
6         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
7     }

關鍵代碼在sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

繼續:

 1 //獲得消息隊列
 2     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
 3         MessageQueue queue = mQueue;
 4         if (queue == null) {
 5             RuntimeException e = new RuntimeException(
 6                     this + " sendMessageAtTime() called with no mQueue");
 7             Log.w("Looper", e.getMessage(), e);
 8             return false;
 9         }
10         return enqueueMessage(queue, msg, uptimeMillis);
11     }

這段代碼主要就是獲取到消息隊列,有了消息隊列咱們接着看enqueueMessage(queue, msg, uptimeMillis);

 

1 //handler和msg創建關聯
2     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
3         msg.target = this;
4         if (mAsynchronous) {
5             msg.setAsynchronous(true);
6         }
7         return queue.enqueueMessage(msg, uptimeMillis);
8     }

 

 msg.target = this;這裏將msg的target指向本身,msg的target只能是this
最後相信你們也看出來了,接下來就是真正將msg插入到消息隊列了
 1 //負責將msg插入到消息隊列
 2      boolean enqueueMessage(Message msg, long when) {
 3         if (msg.target == null) {
 4             throw new IllegalArgumentException("Message must have a target.");
 5         }
 6 
 7         synchronized (this) {
 8          //將msg插入到消息隊列
 9         
10             msg.when = when;
11             Message p = mMessages;
12             boolean needWake;
13             //消息隊列爲鏈式存儲 若是消息隊列中的消息爲0,將msg插入到第一個,並新建一個message對象,將
14             //msg對象的next指向新建的message 等待新msg插入
15             if (p == null || when == 0 || when < p.when) {
16                 // New head, wake up the event queue if blocked.
17                 msg.next = p;
18                 mMessages = msg;
19                 needWake = mBlocked;
20             } else {
21             //將msg插入到隊尾
22                 for (;;) {
23                     prev = p;
24                     p = p.next;
25                     if (p == null || when < p.when) {
26                         break;
27                     }
28                     if (needWake && p.isAsynchronous()) {
29                         needWake = false;
30                     }
31                 }
32                 msg.next = p; // invariant: p == prev.next
33                 prev.next = msg;
34             }
35 
36           
37         }
38         return true;
39     }

繞了這麼大一圈,最後是經過Handler中的消息隊列,將消息成功插入隊尾,至此handler在post的時候實際上

是將r封裝成了一個msg並插入到消息隊列;

另外這裏再提一下Handler第二種方式即複寫handleMessage(Message msg)方法使用

handler.sendMessage(msg);

其源代碼其實就是執行以上的

1 public final boolean sendMessageDelayed(Message msg, long delayMillis)
2     {
3         if (delayMillis < 0) {
4             delayMillis = 0;
5         }
6         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
7     }

重複以上一系列過程,將msg插入到消息隊列;

最後咱們來看一下比較關鍵的消息分發,消息分發是在以上Looper源碼的loop方法中核心方法是:

 msg.target.dispatchMessage(msg);

咱們知道msg的target只能是Handler自己,所以消息分發是在Handler中來完成的;

 1   /**
 2      * Handle system messages here.
 3      */
 4     public void dispatchMessage(Message msg) {
 5         if (msg.callback != null) {
 6             handleCallback(msg);
 7         } else {
 8             if (mCallback != null) {
 9                 if (mCallback.handleMessage(msg)) {
10                     return;
11                 }
12             }
13             handleMessage(msg);
14         }
15     }

第一:if (msg.callback != null 若是你傳入了callback即Runnable,那麼就執行 handleCallback(msg);

即調用r的run方法,一般是handler.post(r);類型的

第二:if (mCallback != null)這種方法容許讓activity等來實現Handler.Callback接口,避免了本身編寫handler重寫handleMessage方法。

第三:handleMessage(msg); 即handler.sendMessage(msg);時調用的。直接回調Handler的handleMessage(msg);方法

至此,Android中的消息機制Looper和Handler相信你已經有了必定的瞭解;

最後咱們再來總結一下

一、Looper 一個線程中只能有一個Looper,用來管理消息隊列

二、Looper從消息隊列裏取出msg,交給Handler來進行分發,分發到Handler所在的線程執行,即建立Handler時的線程;

三、能夠在當前線程中建立消息對象或直接複寫Runnable的run方法,同過Handler將msg和r封裝後的msg插入到消息隊列

相關文章
相關標籤/搜索