Looper: Looper,Handler,MessageQueue三者之间的联系
在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异步消息处理机制完全解析,带你从源码的角度彻底理解
3.Android中为什么主线程不会因为Looper.loop()方法造成阻塞
Looper: Looper,Handler,MessageQueue三者之间的联系的更多相关文章
- 深入了解Looper、Handler、Message之间关系
深入了解Looper.Handler.Message之间关系 前言及简介 上个星期我们整个项目组趁着小假期,驱车去了江门市的台山猛虎峡玩了两个多钟左右极限勇士全程漂流,感觉真得不错,夏天就应该多多玩水 ...
- Android 异步消息处理机制 让你在深入了解 Looper、Handler、Message之间的关系
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 非常多人面试肯定都被问到过,请问And ...
- Handle的原理(Looper、Handler、Message三者关系)
转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介绍 前面的内容对Handler做了介绍,也讲解了如何使 ...
- 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)
Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子. package com.example.loopertest; i ...
- [转]Handler MessageQueue Looper消息循环原理分析
Handler MessageQueue Looper消息循环原理分析 Handler概述 Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler ...
- 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...
- Android 异步消息处理机制终结篇 :深入理解 Looper、Handler、Message、MessageQueue四者关系
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 我们知道更新UI操作我们需要在UI线程中操作,如果在子线程中更新UI会发生异常可能导致崩溃,但是在UI线程中进行耗时操作又会导致ANR,这 ...
- Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
转自:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中的 ...
随机推荐
- tomcat运行一段时间出“org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header”
试了好多种方法,貌似还是没有解决问题,不过也学到了点东西,记录下备忘吧. 异常详情: 1.首先看到最多的就是说在server.xml中的Connector中添加maxHttpHeaderSize=&q ...
- node绑定域名 nginx篇
创建nodejs文件,并测试执行有没有问题. var express = require('express'); var app = express(); app.get('/', function ...
- Oracle数据库使用游标查询结果集所有数据
--Oracle使用游标查询结果集所有数据 DECLARE myTabelName NVARCHAR2():=''; --表名 myTableRowComment NVARCHAR2():=''; - ...
- redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?
redis的过期策略都有哪些? 设置过期时间: set key 的时候,使用expire time,就是过期时间.指定这个key比如说只能存活一个小时?10分钟?指定缓存到期就会失效. redis的过 ...
- xss获取cookie源码附利用代码
保存为cookie.asp <% testfile=Server.MapPath("cookies.txt") msg=Request("msg") se ...
- test20190526 Noip 模拟赛 4
调整(tweak) [问题描述] 已给定一个 N个点 M条边的有向图,点编号为1到N,第i条边为 (ui,vi), 权值为 wi. 你可以进行一次操作,使得任意条边的权值变成非负整数.要求进行尽量少的 ...
- HttpMessageConverter(消息转换器 )和@responsebody使用(转)
@responsebody表示该方法的返回结果直接写入HTTP response body中 一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@resp ...
- c# 异步方法中HttpContext.Current为空
调用异步方法前 HttpContext context = System.Web.HttpContext.Current; HttpRuntime.Cache.Insert("context ...
- 后端程序员常用的linux命令
1. windows ctrl+ - 终端窗口变小 ctrl + shift + = 终端窗口变大 1. mac command+ - 终端窗口变小 command ...
- 计数器的原理,设计及verilog实现
若计数器由n个触发器组成,则计数器的位数为n,所能计数的最大模数为2的n次幂.以下为同步二进制加法计数器电路; 驱动方程:状态图 状态方程(此时的Q0,Q1为上一次状态值): 下例是同步4位2进制计数 ...