在Android中每个应用的UI线程是被保护的,不能在UI线程中进行耗时的操作,其他的子线程也不能直接进行UI操作。为了达到这个目的Android设计了handler Looper这个系统框架,Android 推荐把耗时的操作放到子线程中去执行,子线程执行完毕后如果想通知UI更新,可以通过给主线程的Handler发送Message的方式来予以实现,说起Handler就不得不提到它的另外两个伙伴:Looper和MessageQueue,它们三者之间的关系如下:

Handler: 消息处理者(发送消息和处理消息, 准确的说是发送消息到MessageQueue, 处理Looper从MessageQueue中抽取的消息)。
MessageQueue: 消息队列(承载消息的容器,存放Handler发送的消息)。
Looper: 管理者(管理消息队列,不断的从MessageQueue中抽取消息交给Handler进行处理)。

以子线程向主线程发送一条消息为例,当在一条子线程中调用mHandler.sendMessage(msg)时,它的执行过程如下:

1. Handler会依次调用 sendMessageDelayed() 、 sendMessageAtTime() 、 enqueueMessage() 方法将消息压入MessageQueue。

1.1 sendMessage

    /**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}

1.2 sendMessageDelayed

    /**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

1.3 sendMessageAtTime

    /**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

这里的mQueue其实是Handler已经持有的一个成员变量,在Handler的构造方法中通过Looper对象身上获取到的,Looper对象本身就含有一个MessageQueue。

    /**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

1.4 enqueueMessage

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

在enqueueMessage方法中通过调用MessageQueue的enqueueMessage()方法将消息压入消息队列。

2. 以上是入队的操作,接下来主线程通过Looper.loop()方法不断的从消息队列中获取消息,并交给其指定的Handler进行处理:

这里有个问题,主线程的Looper是什么时候启动的?我们知道,Google设计Looper的目的就是为了在一个线程里运行一个消息循环,但是Looper需要调用 prepare() 方法才能运行起来,调用 loop() 方法开始处理消息。那么这两个方法在哪里开始调用的?

一般说来,Android程序的入口点可以认为是android.app.ActivityThread类的main()方法(Android 2.3):

public static final void main(String[] args) {
SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
} ActivityThread thread = new ActivityThread();
thread.attach(false); if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
} Looper.loop(); if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
} thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}

果然,在这个方法里找到了prepare()和loop()方法的调用,这说明程序在启动的时候就自动开始了Looper的运转。接下来就要看出队的操作了,Looper通过调用loop()方法开始处理消息,来到Looper.java:

2.1 loop()

public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}

可以看到,它内部起了一个死循环,并不断的从队列中获取Message, 然后通过调用  msg.target.dispatchMessage(msg); 方法将消息分发出去, 这里的target就是之前指定处理该消息的Handler, 从这里也可以看出,一个界面可以有很多个Handler,因为最终消息都会被分发到它所指定的那个Handler上面去。

2.2 dispatchMessage

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

这里首先对Message的callback做了判断,如果它自身的callback不为空,就调用handleCallback处理该消息,那什么时候Message的callback不为空呢?其实是在调用Handler的post(Runnable r)方法发送消息的时候:

    /**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}

Handler#post(Runnable r)

    private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

getPostMessage

那这个mCallback是个什么东西呢,它其实是Handler的构造方法中传入的用于处理具体msg的一个类:

    /**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

接下来就很简单了,如果mCallback不为null,就调用了mCallback的handleMessage来处理消息,如果mCallback为null,就直接调用Handler的handleMessage来处理消息,注意到,Handle本身的handleMessage()方法其实是个空方法:

    /**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}

我们一般在使用Handler在处理Message的时候都会将其重写。

总结:整个执行流程就是:

1.Handler先将指定的Message压入到Looper对象的MessageQueue中;

2.Looper对象会调用loop()方法不断的从MessageQueue中获取消息;

3.当拿到一条消息后,会根据该Message的target选择合适的Handler并调用其handleMessage()方法对消息进行处理。

参考链接:

1. 郭神-Android异步消息处理机制完全解析,带你从源码的角度彻底理解

2.Android源代码在线

3.Android中为什么主线程不会因为Looper.loop()方法造成阻塞

Looper: Looper,Handler,MessageQueue三者之间的联系的更多相关文章

  1. 深入了解Looper、Handler、Message之间关系

    深入了解Looper.Handler.Message之间关系 前言及简介 上个星期我们整个项目组趁着小假期,驱车去了江门市的台山猛虎峡玩了两个多钟左右极限勇士全程漂流,感觉真得不错,夏天就应该多多玩水 ...

  2. Android 异步消息处理机制 让你在深入了解 Looper、Handler、Message之间的关系

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 非常多人面试肯定都被问到过,请问And ...

  3. Handle的原理(Looper、Handler、Message三者关系)

    转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介绍 前面的内容对Handler做了介绍,也讲解了如何使 ...

  4. 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)

    Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子. package com.example.loopertest; i ...

  5. [转]Handler MessageQueue Looper消息循环原理分析

    Handler MessageQueue Looper消息循环原理分析   Handler概述 Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler ...

  6. 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...

  7. Android 异步消息处理机制终结篇 :深入理解 Looper、Handler、Message、MessageQueue四者关系

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 我们知道更新UI操作我们需要在UI线程中操作,如果在子线程中更新UI会发生异常可能导致崩溃,但是在UI线程中进行耗时操作又会导致ANR,这 ...

  8. Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  9. Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    转自:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中的 ...

随机推荐

  1. 如何设置CentOS 7获取动态IP和静态IP

    自动获取动态IP地址 1.输入“ip addr”并按回车键确定,发现无法获取IP(CentOS 7默认没有ifconfig命令),记录下网卡名称(本例中为ens33). 2.输入“cd /etc/sy ...

  2. linux系统编程之进程(二)

    今天继续学习进程相关的东东,上节提到了,当fork()之后,子进程复制了父进程当中的大部分数据,其中对于打开的文件,如果父进程打开了,子进程则不需要打开了,是共享的,所以首先先来研究下共享文件这一块的 ...

  3. 微信小程序~基础组件

    (1)视图容器 名称 功能说明 movable-view 可移动的视图容器,在页面中可以拖拽滑动 cover-image 覆盖在原生组件之上的图片视图 cover-view 覆盖在原生组件之上的文本视 ...

  4. P1169 [ZJOI2007]棋盘制作[悬线法/二维dp]

    题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8 \times 88×8大小的黑白相间的方阵,对应八八六十四卦,黑白 ...

  5. MongoDB与Python的交互

    驱动模块 pymongo是python里常用的操作MongoDB的驱动模块 可用pip下载安装 pip install pymongo 创建连接 MongoClient是MongoDB的客户端代理对象 ...

  6. 三种Timer

    一.基于 Windows 的标准计时器(System.Windows.Forms.Timer) 首先注意一点就是:Windows 计时器是为单线程环境设计的.它直接继承自Componet.Timer控 ...

  7. 修改Windows10 命令终端cmd的编码为UTF-8

    1. 临时修改 进入cmd窗口后,直接执行 chcp 2. 永久修改 在运行中输入regedit,找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Pro ...

  8. 再论strlen sizeof

    今天,在使用字符串的时候,对sizeof和strlen的用法更加深入了,特此记录下. strlen是运行是计算的,不能放在函数外面计算的sizeof是预编译时运行的,可以放在函数外面计算. 对于cha ...

  9. 使用Fiddler抓包抓取不了数据包的问题

    一:(我)抓包遇到的问题. ①:抓包一直出现这个问题 解决办法:  如果你遇到上面的问题,就可能是证书的问题(我的本地证书是用系统生成证书的一个软件生成的个人证书,所以出现了问题,我抓的所有数据都出现 ...

  10. 初始SpringBoot

    导入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:/ ...