深入理解Android异步消息处理机制
一。概述
Android 中的异步消息处理主要分为四个部分组成,Message、Hndler、MessageQueue 和 Looper。其关系如下图所示:

1. Message 是线程之间传递的消息,它可以在内部携带少量信息,用于在不同线程之间交换数据。
2. MessageQueue 是消息队列,它主要用于存放所有由 Handler 发送过来的消息,这部分消息会一直在消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象。
3. Handler 是处理者,它主要用于发送和处理消息。 发送消息一般使用 handler 的 sendMessage()方法,处理消息会调用 handleMessage() 方法。
4. Looper 是每个线程中 MessageQueue 的管家, 调用 loop() 方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将其取出,并传递到 handleMessage
()方法当中。每个线程中也只会有一个Looper对象。
二。详细介绍
1、Looper
对于Looper主要是prepare()和loop()两个方法。
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。Looper 就是存储在sThreadLocal里面。这个方法被调用后,首先会判断当前线程里面有没有 Looper对象,如果没有就会创建一
个 Looper 对象,如果存在则会抛出异常。可见,prepare()方法,不能被调用两次。这就保证了一个线程只有一个Looper对象。
接下来我们看一下Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
在 Looper 的构造函数中,创建了 MessageQueue 对象,这也保证了一个线程只有一个 MessageQueue 对象。
然后我们看看 loop() 方法:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
这个方法先调用 myLooper() 方法,得到 sThreadLocal 中保存的 Looper 对象,并得到 looper 对象对应的 MessageQueue 对象,然后就进入无限循环。
该循环主要包括:取出一条消息,如果没有消息则阻塞; 调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。
Looper主要作用:
1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
2、Handler
在使用Handler之前,我们都是初始化一个实例,比如用于更新UI线程,我们会在声明的时候直接初始化,或者在onCreate中初始化Handler实例。
private Handler mHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case value: break; default:
break;
}
};
};
三。小结
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会
存在一个。大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用
了Looper.prepare()和Looper.loop()方法
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,并与Looper实例中的MessageQueue相关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
深入理解Android异步消息处理机制的更多相关文章
- 《Android进阶》之第三篇 深入理解android的消息处理机制
Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 android的消息处理机制(图+源码分析)——Looper,Handler,Message an ...
- Android异步消息处理机制(多线程)
当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如果不将这类操作放在子线程里去执行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用. ...
- 【转载】Android异步消息处理机制详解及源码分析
PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...
- Android 异步消息处理机制终结篇 :深入理解 Looper、Handler、Message、MessageQueue四者关系
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 我们知道更新UI操作我们需要在UI线程中操作,如果在子线程中更新UI会发生异常可能导致崩溃,但是在UI线程中进行耗时操作又会导致ANR,这 ...
- 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
转自:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中的 ...
- Android异步消息处理机制
安卓子线程无法直接更改UI,所以需要异步消息处理机制来解决 <?xml version="1.0" encoding="utf-8"?><Li ...
- Android 异步消息处理机制解析
Android 中的异步消息处理主要由四个部分组成,Message.Handler.MessageQueue.Looper.下面将会对这四个部分进行一下简要的介绍. 1. Message: Messa ...
- Android 异步消息处理机制 让你在深入了解 Looper、Handler、Message之间的关系
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 非常多人面试肯定都被问到过,请问And ...
随机推荐
- js 将base64转为图片
var imgurl = response.data; $(".codeimg").attr('src','data:image/png;base64,'+imgurl); var ...
- 大数据之路day05_1--初识类、对象
1.1 什么是面向对象 面向对象思想就是不断的创建对象(属性与行为的封装,让二者作为整体参与程序执行),使用对象,指挥对象做事情.(在已有对象的情况下,直接使用对象,而不再去考虑对象的内 ...
- 2.基础:Vue组件的核心概念
一.组件基础和注册 组件概念 组件系统是 Vue 的另一个重要概念,他的核心就是封装和复用. 细节 组件的name必须是全局唯一. 二.属性.事件和插槽 组件的三大核心概念:属性.事件和插槽. 属性, ...
- 实现 call、apply、bind
实现 call.apply.bind 在之前一篇文章写了这三个参数的区别,但是其实面试更常考察如何实现.其实所有的原生函数的 polyfill 如何实现,只需要考虑 4 点即可: 基本功能 原型 th ...
- HTTPS加密流程理解
HTTPS加密流程 由于HTTP的内容在网络上实际是明文传输,并且也没有身份验证之类的安全措施,所以容易遭到挟持与攻击 HTTPS是通过SSL(安全套接层)和TLS(安全传输协议)的组合使用,加密TC ...
- 详解Spring Security的HttpBasic登录验证模式
一.HttpBasic模式的应用场景 HttpBasic登录验证模式是Spring Security实现登录验证最简单的一种方式,也可以说是最简陋的一种方式.它的目的并不是保障登录验证的绝对安全,而是 ...
- 开启docker中的mongodb认证授权
前言: 开启MongoDB服务后,默认是没有权限验证的.直接通过IP加端口就可以远程访问数据库,并对数据库进行任意操作.下面介绍一下如何开启docker中MongoDB的权限认证. 安装完MongoD ...
- @Transactional 的回滚
默认情况下,Exception是不会引起回滚操作的,RuntimeException才会引起回滚操作. 当然如果所有的Exception都要回滚的话,直接@Transactional(rollback ...
- docker swarm 过滤器affinity 限制副本不会出现在同一个节点上
affinity:container!=容器服务名称(可以是正则) 举个例子:stack_ds.yaml # cat stack_dsc.yaml version: '3.0' services: t ...
- hdu 1251 统计难题 (字典树(Trie)<PS:C++提交不得爆内存>)
统计难题Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submis ...