Android 消息机制(Handler,Looper,MessageQueue,Message)
2012-12-26 11:40
411 查看
android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,Handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。
消息处理过程如下图所示:
Handler主要涉及到的内容有:
Handler 、 Handler.Callback、AsyncQueryHandler
Looper、
HandlerThread、Runnable
Message、Message queue
Looper
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。
(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。
(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报如下的错误:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
将代码中的mHandler声明成类成员,在主线程通过mHandler发送消息即可。
Handler
Handler在android里负责发送和处理消息。它的主要用途有:
1)按计划发送消息或执行某个Runnanble(使用POST方法);
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)
默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper
只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。
调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)。
1.Handler使用post方法
View
Code
程序运行结果为:
从结果可以看出,使用post方法是将一个Runnable对象依附在主线程上面,并没有开启一个新的线程。注意:如果在Runnable对象中执行耗时的操作的话,还是会弹出ANR对话框。
2.Handler使用sendMessage方法
sendMessage有多种方式:
(一) Handler和sendMessage都在同一个线程里面
(二) Handler在主线程,sendMessage在子线程
(三) Handler在子线程,sendMessage在主线程
对于第一种情况,就是在创建Handler对象的时候重写handleMessage()方法,还是使用的是主线程,所以在处理消息中不能有耗时操作,否则会出现ANR对话框。
对于第二种情况,创建了一个新的线程,可以处理耗时操作,示例代码如下:
View
Code
对于第三种情况,就要涉及到HandlerThread。由于在默认情况下,Handler接受的是当前线程下的消息循环实例,要使用子线程的消息队列,就得使用HandlerThread,它继承于Thread,与普通Thread的差别在于,它有一个Looper成员变量,这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是消息队列+消息循环。(当我们需要一个工作线程时,而不是把它当作一次性消耗品,用过即废弃的话,就可以使用HandlerThread)。
HandlerThread
Android官方文档中Looper的介绍:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
HandlerThread源代码中的run方法代码如下:
public void run() {
mTid = Process.myTid();
Looper.prepare(); //使该线程拥有一个Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //让Looper开始工作,从消息队列里取消息,处理消息
mTid = -1;
}
继承了该类的Thread就拥有了Looper成员变量,可以处理Handler发送的消息。
View
Code
程序运行结果如下:
消息处理过程如下图所示:
Handler主要涉及到的内容有:
Handler 、 Handler.Callback、AsyncQueryHandler
Looper、
HandlerThread、Runnable
Message、Message queue
Looper
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。
(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。
(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报如下的错误:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
将代码中的mHandler声明成类成员,在主线程通过mHandler发送消息即可。
Handler
Handler在android里负责发送和处理消息。它的主要用途有:
1)按计划发送消息或执行某个Runnanble(使用POST方法);
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)
默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper
只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。
调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)。
1.Handler使用post方法
View
Code
程序运行结果为:
从结果可以看出,使用post方法是将一个Runnable对象依附在主线程上面,并没有开启一个新的线程。注意:如果在Runnable对象中执行耗时的操作的话,还是会弹出ANR对话框。
2.Handler使用sendMessage方法
sendMessage有多种方式:
(一) Handler和sendMessage都在同一个线程里面
(二) Handler在主线程,sendMessage在子线程
(三) Handler在子线程,sendMessage在主线程
对于第一种情况,就是在创建Handler对象的时候重写handleMessage()方法,还是使用的是主线程,所以在处理消息中不能有耗时操作,否则会出现ANR对话框。
对于第二种情况,创建了一个新的线程,可以处理耗时操作,示例代码如下:
View
Code
对于第三种情况,就要涉及到HandlerThread。由于在默认情况下,Handler接受的是当前线程下的消息循环实例,要使用子线程的消息队列,就得使用HandlerThread,它继承于Thread,与普通Thread的差别在于,它有一个Looper成员变量,这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是消息队列+消息循环。(当我们需要一个工作线程时,而不是把它当作一次性消耗品,用过即废弃的话,就可以使用HandlerThread)。
HandlerThread
Android官方文档中Looper的介绍:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
HandlerThread源代码中的run方法代码如下:
public void run() {
mTid = Process.myTid();
Looper.prepare(); //使该线程拥有一个Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //让Looper开始工作,从消息队列里取消息,处理消息
mTid = -1;
}
继承了该类的Thread就拥有了Looper成员变量,可以处理Handler发送的消息。
View
Code
程序运行结果如下:
相关文章推荐
- Android 消息机制(Handler,Looper,MessageQueue,Message)
- Handler,Message,Looper,MessageQueue 解析 -Android 异步消息机制
- Android 总结:Message,MessageQueue,Looper,Handler 消息机制
- Android 消息机制(Handler,Looper,MessageQueue,Message)
- Android 消息机制 - Handler, Looper, Message, MessageQueue 的源码分析
- [Android]Handler-Looper-MessageQueue-Message、HandlerThread
- android中MessageQueue,Message,Looper,handler的关系
- Android消息处理机制——Looper,Handler,Message,MessageQueue,Thread
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- 深入理解Android消息队列原理篇:Message、MessageQueue、Looper、Handler
- 【java】Handler,Looper,Message,MessageQueue。【android】HandlerThread+Looper
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- Android中的Looper,Handler,Message和MessageQueue
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- Android Handler处理机制 ( 三 ) ——Handler,Message,Looper,MessageQueue
- android消息处理机制学习(二)-Handler,Message,MessageQueue,Looper图例讲解
- Android之理解Looper、Handler、Message、MessageQueue
- android多线程编程详解,关于Handler ,Looper , Message , MessageQueue