之前用hexo+github来对自己学习的知识做一个记录和整理,但是发现图片上传,文章管理等等略有麻烦,所以在简书也搭一个小窝吧 :)
Handler
关键的概念以及问题的解释
MessageQueue:消息队列,按顺序存放消息实体,由单链表实现。
ThreadLocal:一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储之后只能在指定的线程中可以获取到存储的数据,其他线程无法获取。
Q:系统为什么不允许在子线程中访问UI?
A:因为Android中的UI不是线程安全的,多线程并发访问UI会导致不可预测的后果。那为什么不给UI控件加上锁机制呢?第一锁机制会使得UI访问变得复杂。其次会降低UI访问的效率。于是使用了简单高效的单线程模型来处理UI操作。
Handler运行流程
首先,梳理一下Hnadler的运行流程:
- 新建Handler,通过sendMessage或者post发送消息,Handler调用sendMessageAtTime将Message交给MessageQueue
- MessageQueue.enqueueMessage方法将Message以链表的形式放入队列中
- Looper的loop方法循环调用MessageQueue.next()取出消息,并且调用Handler的dispatchMessage来处理消息
- 在dispatchMessage中,分别判断msg.callback、mCallback也就是post方法或者构造方法传入的不为空就执行他们的回调,如果都为空就执行我们最常用重写的handleMessage。
如图:
handler.png官方API对Hnadler的说明
看看官方api对Handler的说明:
“A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue. ”
一个Handler 允许你发送和处理与线程MessageQueue相关联的Message 和Runnable对象。每个Handler 实例和单个线程和线程的消息队列相关联。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。
There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in the future; and(2) to enqueue an action to be performed on a different thread than your own.
Handler主要有两个作用:1.在工作线程中发送消息 2.在UI线程中获取、处理消息.
- Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
- sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。
View.post
View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。
Handler.post
这里重点学习一下post方法。
先来看看post()源码:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
继续查看getPostMessage():
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Runnable被封装成Message.callback,最后来看看dispatchMessage():
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在dispatchMessage中,对post的msg的callback不为空的情况,调用handleCallback方法
private final void handleCallback(Message message) {
message.callback.run();
}
handleCallback()方法里面直接调用用之前Runnbale里面的run()方法。
sendMessage的源码就不再贴了,从源码上看本,这两者没有多大的区别。
post方法相对实现起来更方便一些。
此外出现post时,run方法不执行的情况,有可能是而是我们初始化对象和这个对象的作用域引起的问题,我们如果不在最开始定义runnable对象的时候就初始化,那就会导致在我们dispatchMessage的时候实际上看到的runnable是null,导致run方法不执行。
后记
Handler的学习先整理到这,有机会继续补充写第二部分。
参考资料:
Android开发艺术探索-任玉刚
google官方api说明
网友评论