Android的Handler机制
来源:互联网 发布:windows凭据无法保存 编辑:程序博客网 时间:2024/05/22 10:58
相信刚接触Android开发的朋友总会有一段时间被关于Handler的异常搞得焦头烂额,本篇博客就说说Handler的那些事,从系统原理和实际开发解读,相信对你会有很大助益。
Handler是Android消息机制的上层接口,所以开发过程中只需要和Handler交互即可。很多人认为Handler的作用是更新UI,但事实上更新UI不过是Handler的一个使用场景罢了。
在Android中主线程要处理界面界面交互相关的逻辑,因此要保证较高的响应速度,一些耗时的操作,比如读取文件或者访问网络,Android要求放到子线程中,当耗时操作完成后可能做一些UI上的改变,但是Android限制不能在子线程访问UI控件,否则会触发异常,这个时候Handler就可以将更新UI的操作切换到主线程来执行。系统不允许在子线程更新UI的原因是Android的UI控件不是线程安全的,如果在不同线程并发访问UI控件可能导致不可预知的状况。当然有人会考虑用加锁来替代,但加锁一会使UI访问的逻辑更加负责,二来加锁会阻塞某些线程的执行。相比还是Hander更简单高效一点。
Handler的运行需要底层MessageQueue和Looper的支撑。MessageQueue翻译过来是消息队列,但他的内部是采用单链表来存储消息列表的。MessageQueue只是一个消息存储单元,它不能去处理消息。这时就用到Looper了,Looper会以无限循环的形式去查找MessageQueue中是否有新消息,如果有的话就交给Handler处理这个消息,否则就等待着。
Handler在创建的时候会采用当前线程的Looper来构造循环消息系统,这可以参见下面Handler的构造函数,但Handler是如何获得这个Looper的呢?这就要用到ThreadLocal了,但他并不是线程,一个ThreadLocal实例可以在不同的线程互不干扰的存储并提供数据副本。所以通过ThreadLocal就可以轻松地获取每个线程的Looper。主线程,也就是UI线程,被创建时就会默认初始化Looper,这也是在主线程默认可以使用Handler的原因。其他的线程如果需要创建Handler就必须先为线程创建Looper。
首先定义一个ThreadLocal对象,选择Boolean类型的,如下所示:
private ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<Boolean>();
接着本别在主线程,线程1和线程2中访问他的值。
运行结果如下:
从日志中可以看出虽然不同线程访问的是同一ThreadLocal对象,但他们获取到的值却不一样,这让我觉得其中的设计一定有绝妙之处。分析过他的源码就可以明白了:
ThreadLocal是一个泛型类,他的定义为pubilc class ThreadLocal<T>,下面是他的set方法:
public void set(T value){
Thread currentThread = Thread.currentThread();
Value value = values(currentThread);
If(values == null){
Values = initializeValues(currentThread);
}
Values.put(this,value);
}
ThreadLocal.Values localValues是Thread类中专门存储ThreadLocal的数据的成员,上面的代码中先判断localValues是否为null,如果是null就先初始化然后存储ThreadLocal的值。get方法同理不再列出。可见数据的写入是和当前线程一对一锁定在一起的,这种代码的思想这的让本人学习了。
下面继续说回Looper,Looper的构造方法中会创建一个MessageQueue对象,并且把当前线程保存起来:
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
而在loop方法中当MessageQueue的next方法返回一条消息就会调用msg.target.dispatchMessage(msg);这里的mag.target就是发送这条消息的Handler,而Handler的diapatchMessage方法是在创建Handler时所使用的Looper(一般是主线程默认生成的Looper)中执行的,这样就成功的在主线程拉取数据并更新UI了。
下面是Handler的默认构造方法:
public Handler (Callback callback,boolean async){
......
mLooper = Looper.myLoop();
If(myLoop== null){
Throw new RuntimeExcption(“Can’t create handler inside thread that has not called Looper.prepare()”);
}
.......
}
看到这里大概就明白为什么在没有Looper的线程中创建Handler会引发程序异常了。
总结一下,整个过程就是主线程创建了Handler mHandler,当子线程利用mHandler发送一条Message类型的消息时该消息会被插入主线程Looper的MessageQueue,主线程的Looper不断查询MessageQueue是否插入新消息,如果有就交给mHandler处理。这种机制常常被用来通过更新UI。
- Android的Handler机制
- android 的handler 机制
- Android的handler机制
- android的handler机制
- Android的Handler机制
- Android的Handler机制
- Android的Handler机制
- android的handler机制
- Android的Handler机制
- Android Handler机制的原理
- [Android]Handler的消息机制
- Android下的Handler机制
- Android通信的Handler机制
- Android handler机制的原理
- 【android】Handler机制的原理
- Android:Handler机制的原理
- Android Handler机制的原理
- android--handler机制的原理
- 使用Instruments来检测内存泄露
- 算法提高 复数四则运算
- 图像处理杂文(一)
- tensorflow
- I/O 多路复用入门——select/poll/epoll
- Android的Handler机制
- 【nodejs课堂】Node.js回调函数
- storm-kafka 的集成
- [SG函数 Trie树合并] SPOJ COT3 Combat on a tree
- java中IO的基本知识点及其个人理解
- 汇编语言基础
- DAX-PowerBI系列
- [网易云课堂]Linux内核分析(二)—— mykernel内核部署及简单时间片轮转程序分析
- leetcode:451. Sort Characters By Frequency解题报告