转 Android的消息处理机制
来自:http://blog.csdn.net/andyhuabing/article/details/7368217
Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。Android通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。
在 Android 系统 ,这些工作由由由Looper 及 Handler 来完成。
先分析Looper类:
主要提供负责线程的消息循环和消息队列
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); // 准备。。。
mHandler = new Handler() {
public void handleMessage(Message msg) { // 消息处理
// process incoming messages here
}
};
Looper.loop(); // 进入消息循环
}
}
下面Looper类的准备函数:
private static final ThreadLocal sThreadLocal = new ThreadLocal();
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
这里利用 ThreadLocal 线程局部存储变量将将Looper与调用线程关联起来。
而消息处理流程如何呢?
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static final void loop() {
Looper me = myLooper(); // 线程中存储的Looper对象
MessageQueue queue = me.mQueue; // Looper类中的消息队列
while (true) {
Message msg = queue.next(); // might block 获取消息
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg); // 利用 Target 注册的方法处理消息
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
可以通过Loop.myLooper()得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。
在android系统,UI线程就是消息的主线程,在 ActivityThread.java 中创建:
public static final void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop(); //消息循环处理
}
-->
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
再来分析 Handler 类:
主要提供负责将消息加入到特定的Looper消息队列中,并分发和处理访消息队列中的消息,构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。
请看如下代码即可明白:
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
这里也同时告诉我们将消息放入到主线程的消息队列中,只需要创建Hanlde对象时以主线程的Looper创建即可。则sendMessage及handleMessage都会在主线程中进行处理。
再看如下变量:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
这里也有 队列,Looper对象及回调函数类,通过 Handler 不同构造函数完成相应的操作。
简化使用队列及消息传递的复杂性,提供方便的调用方法。其中最重要的函数是:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); // 1、利用 Calback 函数处理消息
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { // 2、利用mCallback处理消息
return;
}
}
handleMessage(msg); // 3、利用子类处理消息,这里最常用的方法,直接重载handleMessage函数
}
}
那么这几者的关系是怎么样的呢?
一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。
还有一个问题就是Looper和Handler的同步关系如何处理,在android由HandlerThread类进行解决了。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait(); // 如果新线程还未创建Looper对象,则等待
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
新线程创建运行run函数创建Looper对象:
public void run() {
mTid = Process.myTid();
Looper.prepare();// 这里会创建程的Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); // ok,创建好了则通知,最后调用Looper.loop()进入消息循环
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
这里利用 notifyAll / wait 轻检解决此问题了,所以多多使用用HanlderThread类完成多线程同步问题吧。
培训时学员提出的疑问进行补充说明:
每个线程都可以有自己的消息队列和消息循环,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。
那么除了UI thread(ActivityThread main Looper线程)工作如何运行的呢?
可以参考下 AsyncQueryHandler.java 实现:
private static Looper sLooper = null;
private Handler mWorkerThreadHandler;
// 工作线程,处理消息,减轻UI thread负担
protected class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
...
}
}
//1、构造Looper消息处理线程HandlerThread
public AsyncQueryHandler(ContentResolver cr) {
super();
mResolver = new WeakReference<ContentResolver>(cr);
synchronized (AsyncQueryHandler.class) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
// 这里将会调用到HandlerThread.run()进入到Looper.loop();循环消息处理中
thread.start();
//2、利用thread.getLooper()获取自已的Looper
sLooper = thread.getLooper();
}
}
//3、并设定给WorkerHandler进行构造绑定其Looper对象
mWorkerThreadHandler = createHandler(sLooper);
}
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
//4 利用mWorkerThreadHandler(Handler对象)发送消息
public void startQuery(int token,...){
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY;
...
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
内容补充:
Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。
Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
消息队列(MessageQueue)和消息循环(Looper),但是我们看到每个消息处理的地方都有Handler的存在,它是做什么的呢?
Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。
构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper对象创建。
多个子线程访问主线程的Handler对象,Handler对象管理的Looper对象是线程安全的,不管是添加消息到消息队列还是从消息队列中读取消息都是同步保护的,所以不会出现数据不一致现象。
转 Android的消息处理机制的更多相关文章
- 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...
- 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message
原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解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
在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...
- Android异步消息处理机制
安卓子线程无法直接更改UI,所以需要异步消息处理机制来解决 <?xml version="1.0" encoding="utf-8"?><Li ...
- android基础(六)android的消息处理机制
Android中的消息处理机制由四个部分组成:Message.Handler.MessageQueue和Looper,并且MessageQueue封装在Looper中,我们一般不直接与MQ打交道. 一 ...
- Android 异步消息处理机制解析
Android 中的异步消息处理主要由四个部分组成,Message.Handler.MessageQueue.Looper.下面将会对这四个部分进行一下简要的介绍. 1. Message: Messa ...
随机推荐
- 打包python脚本为exe可执行文件-pyinstaller和cx_freeze示例
本文介绍使用cx_freeze和pyinstaller打包python脚本为exe文件 cx_freeze的使用实例 需要使用到的文件wxapp.py, read_file.py, setup.py ...
- parameter和argument的区别
根据网上一些资料,对parameter和argument的区别,做如下的简单说明.1. parameter是指函数定义中参数,而argument指的是函数调用时的实际参数.2. 简略描述为:param ...
- layout_weight体验(实现按比例显示)
在android开发中LinearLayout很常用,LinearLayout的内控件的android:layout_weight在某些场景显得非常重要,比如我们需要按比例显示.android并没用提 ...
- backbone前端基础框架搭建
前端站点名为:site: 前端框架分为:css.js和img,框架的核心在js文件夹下: js中包括collections.models.views.lib和一个app入口js
- CP="CAO PSA OUR" 用P3P header解决iframe跨域访问cookie
1.IE浏览器iframe跨域丢失Session问题 在开发中,我们经常会遇到使用Frame来工作,而且有时是为了跟其他网站集成,应用到多域的情况下,而Iframe是不能保存Session的因此,网上 ...
- Unity 优化
1. 尽量避免每帧处理比如: function Update() { DoSomeThing(); } 可改为每5帧处理一次: function Update() { == ) { DoSomeThi ...
- C#转换日期类型
日期1999-5-31 11:20转换成 /Date(928120800000+0800)/ 其中928120800000实际上是一个1970 年 1 月 1 日 00:00:00至这个DateTim ...
- Ajax 完整教程
第 1 页 Ajax 简介 Ajax 由 HTML.JavaScript™ 技术.DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应用程序.本文的作者是 ...
- BOM-字节序标记
BOM——Byte Order Mark 字节序标记 首先是什么是字节序? 字节序:与二进制数据在机器存放位置相关的! 可分为两类: 1. 小端字节序: 低地址放低位数据. x86系列的计算机就使用这 ...
- ORA-00257: 归档程序错误。在释放之前仅限于内部连接
今天发现oracle数据库连不上,报错:ORA-00257: 归档程序错误.在释放之前仅限于内部连接 马上联想到可能是空间满了,一看磁盘目录,果然. 解决方法如下: 1:查看归档日志目录. 登陆账号后 ...