Handler机制解析
2015-08-21 12:24
232 查看
1.Handler是Android中用来在线程中传递消息的工具,它提供了一种异步的回调机制,使在完成了一个相对耗时的操作后作出相应和通知。
2.Handler的使用,为了能让handler在线程间传递消息,还需要使用到Looper,messageQueue,message。
Looper是为了指定的单一线程创建一个消息循环,与线程一一对应,在UI线程中会自动建立一个Looper,
而在子线程中则需要手动创建或者使用主线程的Looper。
在Looper与线程进行关联时会同时产生一个messageQueue消息队列,用来存放handler所发送的message,遵循先进先出原则。
message包含必要的描述和属性数据,并且此对象可以被发送给Handler处理,属性字段:arg1、arg2、what、obj、replyTo等。
what是用来保存消息标示的;obj是Object类型的任意对象;replyTo是消息管理器,会关联到一个handler,handler就是处理其中的消息。
通常Message可以直接new出来的,但推荐调用handler中的obtainMessage方法来直接获得Message对象。
(从系统线程池中直接取出,可以避免message的创建和销毁,从而节省资源。)
在主线程(UI)中使用handler很简单,只需要创建一个handler对象,并实现他的handleMessage方法,在该方法中对接收到的消息作出相应处理。
3.handler发送消息的机制。在使用handler.sendEmptyMessage(0);发送一个消息对象后,message对象会被放入一个messageQueue队列中,
而该队列属于某个Lopper对象,每个Looper对象通过ThreadLocal.set(new Looper())跟一个Thread进行绑定,Looper对象所属的线程在Looper.Loop
方法中循环执行从messageQueue消息队列中读取message对象并把message对象交由handler处理,调用handler的dispatchMessage方法。
4.子线程中的handler,当在新建的子线程中建立handler时,程序会报RuntimeException异常,产生这个异常的原因是因为子线程没有建立Looper,
为什么主线程中不会报错 呢?来看一下ActivityThread的源码:
所以想要在子线程中创建一个Handler对象就需要以下这种方式:
在其它线程中Handler使用主线程的Looper,前面我说了在新线程中要新建一个Handler需要调用Looper.prepare();
也有另一种方法就是使用主线程中的Looper,那就不必新建Looper对象了:
使用Message.callback回调
1.使用Message.callback
2.使用Handler.post
2.Handler的使用,为了能让handler在线程间传递消息,还需要使用到Looper,messageQueue,message。
Looper是为了指定的单一线程创建一个消息循环,与线程一一对应,在UI线程中会自动建立一个Looper,
而在子线程中则需要手动创建或者使用主线程的Looper。
在Looper与线程进行关联时会同时产生一个messageQueue消息队列,用来存放handler所发送的message,遵循先进先出原则。
message包含必要的描述和属性数据,并且此对象可以被发送给Handler处理,属性字段:arg1、arg2、what、obj、replyTo等。
what是用来保存消息标示的;obj是Object类型的任意对象;replyTo是消息管理器,会关联到一个handler,handler就是处理其中的消息。
通常Message可以直接new出来的,但推荐调用handler中的obtainMessage方法来直接获得Message对象。
(从系统线程池中直接取出,可以避免message的创建和销毁,从而节省资源。)
在主线程(UI)中使用handler很简单,只需要创建一个handler对象,并实现他的handleMessage方法,在该方法中对接收到的消息作出相应处理。
3.handler发送消息的机制。在使用handler.sendEmptyMessage(0);发送一个消息对象后,message对象会被放入一个messageQueue队列中,
而该队列属于某个Lopper对象,每个Looper对象通过ThreadLocal.set(new Looper())跟一个Thread进行绑定,Looper对象所属的线程在Looper.Loop
方法中循环执行从messageQueue消息队列中读取message对象并把message对象交由handler处理,调用handler的dispatchMessage方法。
4.子线程中的handler,当在新建的子线程中建立handler时,程序会报RuntimeException异常,产生这个异常的原因是因为子线程没有建立Looper,
为什么主线程中不会报错 呢?来看一下ActivityThread的源码:
public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); Looper.loop(); if (Process.supportsProcesses()) { throw new RuntimeException("Main thread loop unexpectedly exited"); } thread.detach(); String name = (thread.mInitialApplication != null) ? thread.mInitialApplication.getPackageName() : "<unknown>"; Slog.i(TAG, "Main thread of " + name + " is now exiting"); }可以看到,在main函数中它已经做了这个事情了,调用 Looper.prepareMainLooper(); Looper.loop();在prepareMainLooper方法中建立了一个looper对象,并且与当前的进程进行绑定,在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用 msg.target.dispatchMessage(msg);进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理,然而Handler是怎样与Looper建立联系呢,打开Handler构造函数中会发现这样一段代码:
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue;当新建Handler对象时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:
public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }若Looper对象没有创建,就会抛出"Can't create handler inside thread that has not called Looper.prepare()"这样一个异常。
所以想要在子线程中创建一个Handler对象就需要以下这种方式:
class MyThread extends Thread { public void run() { // 其它线程中新建一个handler Log.i(TAG, MessageFormat.format("Thread run...", Thread.currentThread().getName())); // 创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper Looper.prepare(); newThreadHandler = new Handler() { public void handleMessage(Message msg) { Log.d(Constant.TAG, MessageFormat.format( "newThreadHandler run...", Thread.currentThread().getName())); } }; Looper.myLooper().loop();// 建立一个消息循环,该线程不会退出 } }
在其它线程中Handler使用主线程的Looper,前面我说了在新线程中要新建一个Handler需要调用Looper.prepare();
也有另一种方法就是使用主线程中的Looper,那就不必新建Looper对象了:
getMainLoopHandler =new Handler(Looper.getMainLooper()){ public void handleMessage(android.os.Message msg) { Log.i(TAG, MessageFormat.format("handleMessage run...", Thread .currentThread().getName())); } //该handleMessage方法将在UI线程中执行 };这时候注意不要在handleMessage做太多的操作,因为它在主线程中执行,会影响主线程执行ui更新操作。
使用Message.callback回调
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }从dispatchMessage定义可以看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback的,也就是说,下面两种写法,没有什么区别:
1.使用Message.callback
Message msg = Message.obtain(newThreadHandler,new Runnable() { @Override public void run() { Log.i(TAG, MessageFormat.format("newThreadHandler.Message.callback.run", Thread.currentThread().getName())); } }); newThreadHandler.sendMessage(msg);
2.使用Handler.post
newThreadHandler.post(new Runnable() { @Override public void run() { Log.i(TAG, MessageFormat.format("newThreadHandler.Message.callback.run", Thread.currentThread().getName())); } });
相关文章推荐
- 图论04——任意指定点到所有其它点的最短路径及距离
- 农业告别代码,成为一个真正的程序猿
- python模块
- Android Support兼容包详解
- PHP的Yii框架的基本使用示例
- POJ1144--Network(Tarjan求割点)
- 计划
- The GNU configure and build system-configure的详细介绍
- 作为一个新人,怎样学习嵌入式Linux?(韦东山)
- POJ 3903 Stock Exchange
- matlab调用C、C++程序——matlab、C混合编译
- LeetCode Basic Calculator II
- Web benchmarking 编译 使用
- 软件工程之三问
- LeetCode Basic Calculator II
- 大约laravel错误的解决方案
- [设计模式] - 创建型模式
- JS实现表单中checkbox对勾选中增加边框显示效果
- Linux--Sys_Read系统调用过程分析
- HYSBZ 1503 郁闷的出纳员 (Splay树)