6.Handler机制
2015-05-29 20:19
323 查看
转载请标明出处:
http://blog.csdn.net/yujun411522/article/details/46049131
本文出自:【yujun411522的博客】
对android开发了解多一些的开发者应该都知道handler在android中的重要性。
Android中的消息机制是针对某一个具体线程的。一个线程只能有一个looper,通过looper来不停取出消息队列中的消息。
在默认创建的线程中是不具备消息队列和消息循环的,如果想让其被这些功能,需要调用Looper.prepare()绑定Looper实例,调用Looper.loop()进入消息循环。
由非UI线程如何与UI线程通信部分我们看出UI线程中有两个原则:
1.不要阻塞ui线程
2.不要在非ui线程修改ui线程元素
那么问题来了:在子线程中进行耗时操作后如何将通知ui线程更新数据呢?这就是handler机制的主要用途。
官方文档给出的用途有两个:
1.在ui线程未来的某个时间点调度message和runnables(postAtTime,postDelay,sendMessageAtTime等);
2.让一个action在另一个子线程中运行(子线程中执行耗时操作,完成之后通知UI thread更新)。
6.1 常见用法
先介绍一下与之配合使用的几个重要概念:
6.1.1 Message和Message队列
message是一个可以包含描述和任意类型数据对象的类,可以将Message发送给handler进行处理。下面从代码角度来分析一下:
1 它实现了Parcelable接口,可以用于系统之间传递数据: public final class Message implements Parcelable;
2 比较中要的成员变量:Handler target(处理该message的handler),Runnable callback(定义runnable,主要作用是将Runnable可以封装成message对象来处理,后面有分析),pubic int what(指明消息类型,使用较多),,public
Object obj(可以是的任意对象);
3 如何创建message对象:虽然提供了public 构造方法,但是建议使用Message.obtain()或者Message.obtain(Message)。因为内部使用了message池,避免了过多的创建message对象。上源码:
它还重载了很多方法,都是调用obtain来实现的如:public static Message obtain(Message)
再看看如果回收:
4 sentToTarget函数:
MessageQueue顾名思义就是Message队列
着重分析两个函数
1 enqueueMessage(Message msg,long when)
可以看出队列是按照时间前后顺序的,时间小的在队首。
2 next()从队列中取出来一个message
for(;;){//不停循环取数据
synchronized (this ) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages ;
if (msg != null ) {
final long when = msg.when;
if (now >= when) {//如果时间该message已经到了到执行时间
mBlocked = false ;//不阻塞
mMessages = msg.next;//队尾指向下一个
msg.next = null ;
if (false ) Log.v( "MessageQueue" , "Returning
message: " + msg);
msg.markInUse();//标记正在使用
return msg;
} else {
//下一次pool时间间隔,native层调用
nextPollTimeoutMillis = ( int ) Math.min(when - now, Integer.MAX_VALUE);
}
}
//....
}
}
6.1.2 Runnable
实际可以看成是message。看看Handler中是如何处理的post(Runnable)
调用的是处理message的方法,再看getPostMessage(Runnable):
尼玛,真省事,就是将Runnable包装到message中,作为该message一个成员变量。
6.1.3 Looper
不断的将messageQueue中的信息取出来执行
重要的变量:
1. static final ThreadLocal<Looper> sThreadLocal;用来存放和线程相关的信息。也就是将线程和Looper绑定到一起。
2. final MessageQueue mQueue 要操作的消息队列。也就是一个looper对应一个messageQuene
重要方法:
1 public static void prepare:
就是将Thread 和looper进行绑定。可以看出一个线程有且只能有一个looper。在和线程进行绑定时调用了Looper的构造方法Looper():
初始化messagequeue,将当前线程赋值给looper对象mThread变量。
再看looper()函数:
2 public static void loop()
{
//先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。
Looper me = myLooper();
if (me == null ) {
throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me. mQueue;
while (true ) {
//从queue中取message并进行分发message
Message msg = queue.next(); // might block
if (msg != null ) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return ;
}
//分发message
msg.target.dispatchMessage(msg);
//回收
msg.recycle();
}
}
}
先看myLooper():就是返回线程所绑定的looper实例,可以看出如果没有绑定则报错。
再看dispatchMessage(msg)这个方法实际是Handler类中定义的(message中的target对象就是Handler类型)。
3 public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//执行message中callback中的run()方法
handleCallback(msg);// message.callback.run();
} else {
if (mCallback != null) {
//如果创建handler时指定了callback,执行该callback中的handleMessage,返回
if (mCallback .handleMessage(msg)) {
return;
}
}
//message中没有定义callback(runnable)时才执行自己实现的handleMessage。
handleMessage(msg);
}
}
其中 mCallback 是Callback类型
public interface Callback
{
public boolean handleMessage (Message
msg);
}
4 Looper中还有一个重要的方法,这个方法一般不用,但在后面的分析中会涉及到:prepareMainLooper()
我们在主线程中创建looper对象时并没有主动调用prepare方法,是因为这里已经实例化一个mainLooper对象给主线程使用。
6.1.4 Handler类
handler类的主要作用就是发送和处理message对象的。
先看看有哪些重要的成员变量
1 final Looper mLooper:该线程绑定的Looper实例
2 final MessageQueue mQueue:mLooper中的成员变量
3 final Callback mCallback:自定义handleMessage方法接口
再来看重要的方法
1 构造方法:public Handler(),
public Handler(){
//..
mLooper=Looper.myLooper();//获得该线程绑定的Looper实例
if(mLooper==null){
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback=null;
}
2 带参数的构造方法:public Handler(Looper,Callback)
public Handler(Looper looper,Callback callback){
mLooper=looper;
mQueue = looper.mQueue;
mCallback= callback;
}
3 发送消息(Runnable实际上也是消息,这里不再分析),有好几种方式,最终都是sendMessageAtTime(Message,Long)
public boolean sendMessageAtTime(Message
msg, long uptimeMillis)
{
boolean sent = false ;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this ;//该message对象的target成员变量设置为此handler实例
sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log. w("Looper", e.getMessage(), e);
}
return sent;
}
2 handleMessage(Message)
根据取出来的message对象进行消息处理,一般override
典型用法:
1.子线程中:
class MyThread extends Thread{
public Handler mHanlder;
public void run(){
//将线程与Looper绑定。
//此方法必须在handler创建之前调用,handler否则实例化报错
Looper.prepare();
mHandler = new Handler(){
public void handleMessage(Message msg){
//处理消息
}
};
//不停的取出该线程中message队列中的消息。
Looper.loop();
}
}
2 主线程中直接实例化Handler,这里简要介绍一个为什么不需要Looper.prepare和Looper.loop.
是因为在程序启动已经做了这些工作,在ActivityThread类中main方法:
public static void main(String[] args) {
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
Looper.loop();
}
6.2 流程分析
下面以一个具体案例来分析怎么调用的:
比如说在子线程中发送一个消息给UI线程:
首先UI线程中定义了一个Handler:
private Handler handler = new Handler(){
public void handleMessage(Message msg){
if(msg.what=1){
tv.setText("数据下载完毕");
}
}
};
需要在子线程中执行耗时操作:
new Thread(){
public void run(){
try{
//模拟耗时操作
Thread.sleep(10*1000);
//发送消息,通知UI线程更新
handler.sendEmptyMessage(1);
}catch(Exception e){
}
}
}.start();
流程分析:
1该UI线程中的Looper.prepareMainLooper();和 Looper.loop(); 执行,这样就不需要在实例化handler时调用了prepare和looper。线程中已经有一个looper实例,且已经开始不停的从messageQueue中读取message。
2.子线程中给通过UI线程的handler变量调用handler.sendMessage系类方法,给Ui线程的消息队里发送一个消息。
3.Looper.loop方法调用messageQueue的next()方法取消息,取出来之后调用handler的dispatchMessage方法。
4.执行dispatchMessage方法,由于message中callback ==null,所以执行override的handleMessage方法,更新textview。
http://blog.csdn.net/yujun411522/article/details/46049131
本文出自:【yujun411522的博客】
对android开发了解多一些的开发者应该都知道handler在android中的重要性。
Android中的消息机制是针对某一个具体线程的。一个线程只能有一个looper,通过looper来不停取出消息队列中的消息。
在默认创建的线程中是不具备消息队列和消息循环的,如果想让其被这些功能,需要调用Looper.prepare()绑定Looper实例,调用Looper.loop()进入消息循环。
由非UI线程如何与UI线程通信部分我们看出UI线程中有两个原则:
1.不要阻塞ui线程
2.不要在非ui线程修改ui线程元素
那么问题来了:在子线程中进行耗时操作后如何将通知ui线程更新数据呢?这就是handler机制的主要用途。
官方文档给出的用途有两个:
1.在ui线程未来的某个时间点调度message和runnables(postAtTime,postDelay,sendMessageAtTime等);
2.让一个action在另一个子线程中运行(子线程中执行耗时操作,完成之后通知UI thread更新)。
6.1 常见用法
先介绍一下与之配合使用的几个重要概念:
6.1.1 Message和Message队列
message是一个可以包含描述和任意类型数据对象的类,可以将Message发送给handler进行处理。下面从代码角度来分析一下:
1 它实现了Parcelable接口,可以用于系统之间传递数据: public final class Message implements Parcelable;
2 比较中要的成员变量:Handler target(处理该message的handler),Runnable callback(定义runnable,主要作用是将Runnable可以封装成message对象来处理,后面有分析),pubic int what(指明消息类型,使用较多),,public
Object obj(可以是的任意对象);
3 如何创建message对象:虽然提供了public 构造方法,但是建议使用Message.obtain()或者Message.obtain(Message)。因为内部使用了message池,避免了过多的创建message对象。上源码:
它还重载了很多方法,都是调用obtain来实现的如:public static Message obtain(Message)
再看看如果回收:
4 sentToTarget函数:
MessageQueue顾名思义就是Message队列
着重分析两个函数
1 enqueueMessage(Message msg,long when)
可以看出队列是按照时间前后顺序的,时间小的在队首。
2 next()从队列中取出来一个message
for(;;){//不停循环取数据
synchronized (this ) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages ;
if (msg != null ) {
final long when = msg.when;
if (now >= when) {//如果时间该message已经到了到执行时间
mBlocked = false ;//不阻塞
mMessages = msg.next;//队尾指向下一个
msg.next = null ;
if (false ) Log.v( "MessageQueue" , "Returning
message: " + msg);
msg.markInUse();//标记正在使用
return msg;
} else {
//下一次pool时间间隔,native层调用
nextPollTimeoutMillis = ( int ) Math.min(when - now, Integer.MAX_VALUE);
}
}
//....
}
}
6.1.2 Runnable
实际可以看成是message。看看Handler中是如何处理的post(Runnable)
调用的是处理message的方法,再看getPostMessage(Runnable):
尼玛,真省事,就是将Runnable包装到message中,作为该message一个成员变量。
6.1.3 Looper
不断的将messageQueue中的信息取出来执行
重要的变量:
1. static final ThreadLocal<Looper> sThreadLocal;用来存放和线程相关的信息。也就是将线程和Looper绑定到一起。
2. final MessageQueue mQueue 要操作的消息队列。也就是一个looper对应一个messageQuene
重要方法:
1 public static void prepare:
就是将Thread 和looper进行绑定。可以看出一个线程有且只能有一个looper。在和线程进行绑定时调用了Looper的构造方法Looper():
初始化messagequeue,将当前线程赋值给looper对象mThread变量。
再看looper()函数:
2 public static void loop()
{
//先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。
Looper me = myLooper();
if (me == null ) {
throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me. mQueue;
while (true ) {
//从queue中取message并进行分发message
Message msg = queue.next(); // might block
if (msg != null ) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return ;
}
//分发message
msg.target.dispatchMessage(msg);
//回收
msg.recycle();
}
}
}
先看myLooper():就是返回线程所绑定的looper实例,可以看出如果没有绑定则报错。
再看dispatchMessage(msg)这个方法实际是Handler类中定义的(message中的target对象就是Handler类型)。
3 public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//执行message中callback中的run()方法
handleCallback(msg);// message.callback.run();
} else {
if (mCallback != null) {
//如果创建handler时指定了callback,执行该callback中的handleMessage,返回
if (mCallback .handleMessage(msg)) {
return;
}
}
//message中没有定义callback(runnable)时才执行自己实现的handleMessage。
handleMessage(msg);
}
}
其中 mCallback 是Callback类型
public interface Callback
{
public boolean handleMessage (Message
msg);
}
4 Looper中还有一个重要的方法,这个方法一般不用,但在后面的分析中会涉及到:prepareMainLooper()
我们在主线程中创建looper对象时并没有主动调用prepare方法,是因为这里已经实例化一个mainLooper对象给主线程使用。
6.1.4 Handler类
handler类的主要作用就是发送和处理message对象的。
先看看有哪些重要的成员变量
1 final Looper mLooper:该线程绑定的Looper实例
2 final MessageQueue mQueue:mLooper中的成员变量
3 final Callback mCallback:自定义handleMessage方法接口
再来看重要的方法
1 构造方法:public Handler(),
public Handler(){
//..
mLooper=Looper.myLooper();//获得该线程绑定的Looper实例
if(mLooper==null){
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback=null;
}
2 带参数的构造方法:public Handler(Looper,Callback)
public Handler(Looper looper,Callback callback){
mLooper=looper;
mQueue = looper.mQueue;
mCallback= callback;
}
3 发送消息(Runnable实际上也是消息,这里不再分析),有好几种方式,最终都是sendMessageAtTime(Message,Long)
public boolean sendMessageAtTime(Message
msg, long uptimeMillis)
{
boolean sent = false ;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this ;//该message对象的target成员变量设置为此handler实例
sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log. w("Looper", e.getMessage(), e);
}
return sent;
}
2 handleMessage(Message)
根据取出来的message对象进行消息处理,一般override
典型用法:
1.子线程中:
class MyThread extends Thread{
public Handler mHanlder;
public void run(){
//将线程与Looper绑定。
//此方法必须在handler创建之前调用,handler否则实例化报错
Looper.prepare();
mHandler = new Handler(){
public void handleMessage(Message msg){
//处理消息
}
};
//不停的取出该线程中message队列中的消息。
Looper.loop();
}
}
2 主线程中直接实例化Handler,这里简要介绍一个为什么不需要Looper.prepare和Looper.loop.
是因为在程序启动已经做了这些工作,在ActivityThread类中main方法:
public static void main(String[] args) {
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
Looper.loop();
}
6.2 流程分析
下面以一个具体案例来分析怎么调用的:
比如说在子线程中发送一个消息给UI线程:
首先UI线程中定义了一个Handler:
private Handler handler = new Handler(){
public void handleMessage(Message msg){
if(msg.what=1){
tv.setText("数据下载完毕");
}
}
};
需要在子线程中执行耗时操作:
new Thread(){
public void run(){
try{
//模拟耗时操作
Thread.sleep(10*1000);
//发送消息,通知UI线程更新
handler.sendEmptyMessage(1);
}catch(Exception e){
}
}
}.start();
流程分析:
1该UI线程中的Looper.prepareMainLooper();和 Looper.loop(); 执行,这样就不需要在实例化handler时调用了prepare和looper。线程中已经有一个looper实例,且已经开始不停的从messageQueue中读取message。
2.子线程中给通过UI线程的handler变量调用handler.sendMessage系类方法,给Ui线程的消息队里发送一个消息。
3.Looper.loop方法调用messageQueue的next()方法取消息,取出来之后调用handler的dispatchMessage方法。
4.执行dispatchMessage方法,由于message中callback ==null,所以执行override的handleMessage方法,更新textview。
相关文章推荐
- 5.UI线程和非UI线程的交互方式
- 【STL源码剖析读书笔记】自己实现queue之MyQueue(底层用MyList)
- 【STL源码剖析读书笔记】自己实现queue之MyQueue(底层用MyList)
- TOOLS STORE OPENCART 2.X 主题模板 ABC-0628
- codeforces 525B Pasha and String
- 黑马程序员——OC 基础:setter和getter方法
- testNG中@Factory详解
- 多个物体透明度缓冲
- 【优波尔】JavaScript的笔记 (1) 简介 用法 输出 语法
- codeforces 525C Ilya and Sticks
- C++字符串旋转3种方法实现
- 算法导论14(数据结构的扩张)
- C#面向对象编程练习
- Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?
- 浏览器的兼容性问题实质是CSS的兼容性问题,不是Html的兼容性问题
- 浏览器的兼容性问题实质是CSS的兼容性问题,不是Html的兼容问题
- Codeforces Round #305 (Div. 2) E题(数论+容斥原理)
- String类
- 用Java实现了MySql的jdbc
- 最大值最小化