在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. tomcat运行一段时间出“org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header”

    试了好多种方法,貌似还是没有解决问题,不过也学到了点东西,记录下备忘吧. 异常详情: 1.首先看到最多的就是说在server.xml中的Connector中添加maxHttpHeaderSize=&q ...

  2. node绑定域名 nginx篇

    创建nodejs文件,并测试执行有没有问题. var express = require('express'); var app = express(); app.get('/', function ...

  3. Oracle数据库使用游标查询结果集所有数据

    --Oracle使用游标查询结果集所有数据 DECLARE myTabelName NVARCHAR2():=''; --表名 myTableRowComment NVARCHAR2():=''; - ...

  4. redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

    redis的过期策略都有哪些? 设置过期时间: set key 的时候,使用expire time,就是过期时间.指定这个key比如说只能存活一个小时?10分钟?指定缓存到期就会失效. redis的过 ...

  5. xss获取cookie源码附利用代码

    保存为cookie.asp <% testfile=Server.MapPath("cookies.txt") msg=Request("msg") se ...

  6. test20190526 Noip 模拟赛 4

    调整(tweak) [问题描述] 已给定一个 N个点 M条边的有向图,点编号为1到N,第i条边为 (ui,vi), 权值为 wi. 你可以进行一次操作,使得任意条边的权值变成非负整数.要求进行尽量少的 ...

  7. HttpMessageConverter(消息转换器 )和@responsebody使用(转)

    @responsebody表示该方法的返回结果直接写入HTTP response body中 一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@resp ...

  8. c# 异步方法中HttpContext.Current为空

    调用异步方法前 HttpContext context = System.Web.HttpContext.Current; HttpRuntime.Cache.Insert("context ...

  9. 后端程序员常用的linux命令

    1. windows   ctrl+ -  终端窗口变小      ctrl + shift + =  终端窗口变大 1. mac   command+ -  终端窗口变小      command  ...

  10. 计数器的原理,设计及verilog实现

    若计数器由n个触发器组成,则计数器的位数为n,所能计数的最大模数为2的n次幂.以下为同步二进制加法计数器电路; 驱动方程:状态图 状态方程(此时的Q0,Q1为上一次状态值): 下例是同步4位2进制计数 ...