一、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 消息机制的更多相关文章

  1. Android消息机制

    每一个Android应用在启动的时候都会创建一个线程,这个线程被称为主线程或者UI线程,Android应用的所有操作默认都会运行在这个线程中. 但是当我们想要进行数据请求,图片下载,或者其他耗时操作时 ...

  2. Android消息机制:Looper,MessageQueue,Message与handler

    Android消息机制好多人都讲过,但是自己去翻源码的时候才能明白. 今天试着讲一下,因为目标是讲清楚整体逻辑,所以不追究细节. Message是消息机制的核心,所以从Message讲起. 1.Mes ...

  3. Android消息机制不完全解析(上)

        Handler和Message是Android开发者常用的两个API,我一直对于它的内部实现比较好奇,所以用空闲的时间,阅读了一下他们的源码.    相关的Java Class: androi ...

  4. Android消息机制不完全解析(下)

    接着上一篇文章Android消息机制不完全解析(上),接着看C++部分的实现. 首先,看看在/frameworks/base/core/jni/android_os_MessageQueue.cpp文 ...

  5. Android 消息机制 (Handler、Message、Looper)

    综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidne ...

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

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

  7. 【腾讯Bugly干货分享】经典随机Crash之二:Android消息机制

    本文作者:鲁可--腾讯SNG专项测试组 测试工程师 背景 承上经典随机Crash之一:线程安全 问题的模型 好几次灰度top1.top2 Crash发生场景:在很平常.频繁的使用页面,打开一个界面,马 ...

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

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

  9. 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 进程间 通讯 ...

  10. Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)

    不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...

随机推荐

  1. 在DataGridView控件中加入ComboBox下拉列表框的实现

    在DataGridView控件中加入ComboBox下拉列表框的实现 转自:http://www.cnblogs.com/luqingfei/archive/2007/03/28/691372.htm ...

  2. Windows Phone Foreground Toast

    Basically ToastPrompt is an UI component that derives from the Coding4Fun toolkit's abstract PopUp&l ...

  3. 【androidstudio】将eclipse的项目导入android studio

    一.概述 最近正在实习公司迭代一个app,项目工程比较大,依赖的第三方服务.第三方库较多,比较复杂.因为公司项目一直是在ec上写的,没有android studio的版本.而大家都知道ec写代码远没有 ...

  4. AlertDialog使用时遇到问题

    1.其内de子控件高宽度为0? AlertDialog.Builder builder = new AlertDialog.Builder(StoryActivity.this); View view ...

  5. Defining custom settings in Odoo

    Unfortunately Odoo documentation doesn’t seem to include any information about adding new configurat ...

  6. markdown语法学习笔记

    ##1.**标题** # 一级标题 ## 二级标题   ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 ##2.**加粗** 首尾各加两个*号   ##3.*斜字体 ...

  7. Intent实现Activity组件之间的通信

    今天讲解的是使用Intent实现Activity组件之间的通信. 一.         使用Intent显式启动Activity,Activity1àActivity2 1.             ...

  8. Orale介绍

    Oracle数据库: 是甲骨文公司的一款关系数据库管理系统 具有网格计算的框架 数据量大,并发操作比较多,实时性要求高,采取ORACLE数据库 Oracle数据库的体系结构包括物理存储结构和逻辑存储结 ...

  9. DBHelper.java(数据库连接类)

    package com.vcredit.ddcash.batch.util; import java.sql.Connection;import java.sql.DriverManager;impo ...

  10. Bootstrap carousel轮转图的使用

    来自:慕课网http://www.imooc.com/code/5395 图片轮播效果在Web中常常能看到,很多人也称之为幻灯片.其主要显示的效果就是多幅图片轮回播放, 从右向左播放,鼠标悬停在图片时 ...