android 消息机制
一、Android应用程序的主线程主要用于更新UI界面,并且主线程不能做耗时操作,否则会引起ANR;这种情况下需要开一个子线程来进行耗时操作,动作完成之后,子线程发消息给主线程通知其更新UI显示,常见方法有:
- Activity.runOnUiThread(Runnable);
- View.post(Runnable);
- View.postDelayed(Runnable, long);
- Handler消息机制。
注:经过看源码,会发现Activity.runOnUiThread(Runnable),View.post(Runnable),View.postDelayed(Runnable, long)最终本质上会调用到Handler发送消息的方法,如下代码:
Activity.runOnUiThread(Runnable);
/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
*
* @param action the action to run on the UI thread
*/
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
View.Post(Runnable),View.PostDelayed(Runnable); 请忽略attachInfo判断。
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
二、弄清消息机制之前,提一个问题:如何在子线程实例化一个Handler发送message呢?代码很简单,如下
new Thread(){
@Override
public void run() {
super.run();
Looper.prepare();
new Handler().sendEmptyMessage(1);
Looper.loop();
}
}.start();
接下来,问题又来了:
1.发消息的时候为什么要调用Looper.prepare();
2.消息发送后为什么要调用Looper.loop();
3.为什么在主线程里发送信息,我们没有调用 这两个方法呢?
在解答这三个问题之前,先看一张图,大致了解一下消息机制是如何运行的?如下图:

总结一下上面那个图片:在UI线程中有一个消息队列MessageQueue,其它线程do something之后,在UI线程中的消息队列MessageQueue插入Message,而Looper负责轮循消息队列MessageQueue。然后来回答上面第1个问题,看代码:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//初始化Looper,并且初始化消息队列
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
通过上图可得知,接收一个消息的前提是,该线程得拥有自己的消息队列MessageQueue,而第1个问题的答案就是创建一个该线程接收消息的一个消息队列。然后第二个问题请看以下代码:
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.recycleUnchecked();
}
}
通过上图可知消息机制中除了消息队列MessageQueue,还得有轮循,第二个问题就是执行轮循的操作。第三个问题请往下看代码:
public final class ActivityThread {
......
public static final void main(String[] args) {
......
//将当前线程初始化为Looper线程。最终会调用Looper.prepare()
Looper.prepareMainLooper();
......
// 开始循环处理消息队列
Looper.loop();
......
}
}
第三个问题的答案:android应用程序启动过程中,会在进程中执行ActivityThread中main方法,来初始化该应用中UI线程的Looper。这也就是为什么主线程里可以直接调用Handler,而子线程不能直接调用Handler发送消息。
参考:http://3dobe.com/archives/74/
android 消息机制的更多相关文章
- Android消息机制
每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时 ...
- Android消息机制:Looper,MessageQueue,Message与handler
Android消息机制好多人都讲过,但是自己去翻源码的时候才能明白. 今天试着讲一下,因为目标是讲清楚整体逻辑,所以不追究细节. Message是消息机制的核心,所以从Message讲起. 1.Mes ...
- Android消息机制不完全解析(上)
Handler和Message是Android开发者常用的两个API,我一直对于它的内部实现比较好奇,所以用空闲的时间,阅读了一下他们的源码. 相关的Java Class: androi ...
- Android消息机制不完全解析(下)
接着上一篇文章Android消息机制不完全解析(上),接着看C++部分的实现. 首先,看看在/frameworks/base/core/jni/android_os_MessageQueue.cpp文 ...
- Android 消息机制 (Handler、Message、Looper)
综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidne ...
- Android开发之漫漫长途 ⅥI——Android消息机制(Looper Handler MessageQueue Message)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- 【腾讯Bugly干货分享】经典随机Crash之二:Android消息机制
本文作者:鲁可--腾讯SNG专项测试组 测试工程师 背景 承上经典随机Crash之一:线程安全 问题的模型 好几次灰度top1.top2 Crash发生场景:在很平常.频繁的使用页面,打开一个界面,马 ...
- Android开发之漫漫长途 Ⅶ——Android消息机制(Looper Handler MessageQueue Message)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- android 进程间通信 messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯? android 消息机制 进程间 android 进程间 可以用 handler么 messenger 与 handler 机制 messenger 机制 是不是 就是 handler 机制 或 , 是不是就是 消息机制 android messenge
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ...
- Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)
不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...
随机推荐
- 搜索框js样式(通用型)
HTML部分代码: -------------------------------------------------------------- <div class="search_ ...
- REST
REST (REpresentational State Transfer). 为REST模式的Web服务与复杂的SOAP和XML-RPC对比来讲明显的更加简洁. "设计良好的网络应用表现为 ...
- 链接后加"/"与不加"/"的区别
1.http://www.abc.com/abc2.http://www.abc.com/abc/ 当Web服务器接收到对某个末尾不含斜杠的url请求时,例如“http://www.abc.com/a ...
- Unity3D着色器Shader编程入门(一)
自学Unity3D也有大半年了,对Shader一直不敢入坑,最近看了些资料,以及通过自己的实践,对Shader还是有一点了解了,分享下仅作入门参考. 因Shader是对图像图像渲染的,学习前可以去了解 ...
- 2_STL容器
STL算法的精髓在于 算法的 返回值!!! String: string是STL的字符串类型,通常用来表示字符串:C语言中一般用char* char*字符指针;string是类封装了char*,管 ...
- mysql导数据库用到的语句
将字段格式为2013-08-09 13:22:55转换为时间戳 UPDATE `AttendClass` SET `regdate` = unix_timestamp(regDate2) WHERE ...
- decode 函数将字符串从某种编码转为 unicode 字符
环境:Ubuntu, Python 2.7 基础知识 这个程序涉及到的知识点有几个,在这里列出来,不详细讲,有疑问的直接百度会有一堆的. 1.urllib2 模块的 request 对像来设置 HTT ...
- Linux学习笔记---用户管理---帐号管理
root管理 (1)新增用户:useradd -u 指定UID -g 指定GID -G 作为组员添加到某个组 -M 不创建主用户目录 -m 创建主用户目录 -c 用户信息说明列 -d 指定某个目录为主 ...
- 剑指offer?
1. 在一个m*n二维数组中,每一行都按照从左到右的递增顺排序,每一列都按照从上到下的顺序排序,请完成一个函数,输入这样一个二维数组和一个整数,判断数组中是否含有该整数.1 2 8 92 4 9 12 ...
- 剑指offer:大恒图像
大恒图像:成立于1991年,专注于视觉部件.视觉系统及互联网医疗相关产品研发.生产和营销的高科技企业. 旗下产品信息: 1.图像采集卡 摄像机等输入的模拟图像信号经过A/D转换,或将数字摄像机的输出信 ...