Android消息机制源码分析

本篇主要介绍Android中的消息机制,即Looper、Handler是如何协同工作的;

Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper

Handler:用来将消息(Message)插入到当前线程的消息队列,并负责分发Looper中的消息,将消息发送到当前线程执行

具体关系图如下所示:

接下来我们来分析一下Looper和Handler的源码,了解一下其中的奥妙。

首先我们从一个程序运行的入口来分析,源码如下:

public static void main(String[] args){

    ......
    Looper.prepareMainLooper();//初始化Looper

    ......
    if(smainThreadHandler==null){
    smainThreadHandler=thread.getHandler();//初始化Handler
    }

    ......

    Looper.loop();//消息循环执行
    }

可以看出,程序在运行的时候首先会创建主线程的Looper对象,并通过Looper开启消息循环,不停的取出消息并执行;

接下来我们来研究Looper的源码;

第一部分:Looper源码

初始化

 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对象,并从中循环取出消息,并执行,程序就这样跑起来了,具体是如何分发消息的

我们将会在下面讲解;

至此我们至少应该明白,当主线程在执行的时候

1、初始化Looper,并将Looper保存的线程变量中

2、Looper在初始化的时候会创建消息队列,并管理消息队列

2、取出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相信你已经有了一定的了解;

最后我们再来总结一下

1、Looper 一个线程中只能有一个Looper,用来管理消息队列

2、Looper从消息队列里取出msg,交给Handler来进行分发,分发到Handler所在的线程执行,即创建Handler时的线程;

3、可以在当前线程中创建消息对象或直接复写Runnable的run方法,同过Handler将msg和r封装后的msg插入到消息队列

时间: 2024-10-13 23:10:41

Android消息机制源码分析的相关文章

[Android]简略的Android消息机制源码分析

相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.java framework/base/core/java/andorid/os/Message.java framework/base/core/java/andorid/os/MessageQueue.java libcore/luni/src/main/java/java/lang/ThreadLo

Android -- 消息处理机制源码分析(Looper,Handler,Message)

android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类.下面一一介绍: Looper Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线程.在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Lo

拨云见日---android异步消息机制源码分析

做过windows GUI的同学应该清楚,一般的GUI操作都是基于消息机制的,应用程序维护一个消息队列,开发人员编写对应事件的回调函数就能实现我们想要的操作 其实android系统也和windows GUI一样,也是基于消息机制,今天让我们通过源码来揭开android消息机制的神秘面纱 谈起异步消息,就不能不提及Handler,在安卓中,由于主线程中不能做耗时操作,所以耗时操作必须让子线程执行,而且只能在主线程(即UI线程)中执行UI更新操作,通过Handler发送异步消息,我们就能更新UI,一

Handler消息机制源码分析

public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 先来个Handler执行过程的总结: 1. Looper.prepare()方法 为当前线程绑定looper, 在looper构造方法中创建一个messageQueue 2. 创建handler 重并写handleMessage方法 3. 使用handler发送消息,最终消息都会发送至messageQueue对象中,在messageQueue当

Android Handler消息机制源码解析

好记性不如烂笔头,今天来分析一下Handler的源码实现 Handler机制是Android系统的基础,是多线程之间切换的基础.下面我们分析一下Handler的源码实现. Handler消息机制有4个类合作完成,分别是Handler,MessageQueue,Looper,Message Handler : 获取消息,发送消息,以及处理消息的类 MessageQueue:消息队列,先进先出 Looper : 消息的循环和分发 Message : 消息实体类,分发消息和处理消息的就是这个类 主要工

Android 中View的绘制机制源码分析 三

到目前为止,measure过程已经讲解完了,今天开始我们就来学习layout过程,不过在学习layout过程之前,大家有没有发现我换了编辑器,哈哈,终于下定决心从Html编辑器切换为markdown编辑器,这里之所以使用"下定决心"这个词,是因为毕竟Html编辑器使用好几年了,很多习惯都已经养成了,要改变多年的习惯确实不易,相信这也是还有很多人坚持使用Html编辑器的原因.这也反应了一个现象,当人对某一事物非常熟悉时,一旦出现了新的事物想取代老的事物时,人们都有一种抵触的情绪,做技术的

Android 中View的绘制机制源码分析 二

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要讲解了View的measure过程,今天我们就来学习ViewGroup的measure过程,由于ViewGroup只是一个抽象类,所以我们需要以一个具体的布局来分析measure过程,正如我上篇文章说的,我打算使用LinearLayout为例讲解measure过程,如果你还没有读过上篇文章,那么建议你先

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法 1.spreadOutApp尽量平均分配到每个executor上: 2.非spreadOutApp尽量在使用单个executor的资源. 源码分析 org.apache.spark.deploy.master.Master 1.首先判断,master状态不是ALIVE的话,直接返回2.调度driver3. Application的调度机制(核心之核心,重中之重) 源码如下: 1 /*

Android 开源项目源码分析第一期正式发布

由 Trinea 发起.几十名 Android 开发者参与的Android 开源项目源码分析第一期正式发布. 从简介.总体设计.流程图.详细设计全方面分析开源库源码,第一期包括 10 个著名开源库及 5 个公共技术点的全面介绍. 分析文档 作者 Volley 源码解析 grumoon Universal Image Loader 源码分析 huxian99 Dagger 源码解析 扔物线 EventBus 源码解析 Trinea xUtils 源码解析 Caij ViewPagerindicat