目录
前言
Android 开发离不开handler,那什么是handler呢?下面是google对handler的定义:
处理程序允许您发送和处理与线程的{@link MessageQueue}关联的{@link Message}和可运行对象。每个处理程序实例都与一个线程和该线程的消息队列相关联。
简单可以理解为消息传递的工具。
应用场景按功能可以分为两种:
1、延时执行;
2、在子线程通知更新UI;
Handler使用
以下根据我常用的方式介绍:
handler的初始化及接收:
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case 100:
break;
}
}
});
handler发送消息:
1、发送空消息或延时执行:
mHandler.sendEmptyMessage(100);
//第一个参数what 第二个参数间隔时间毫秒值
mHandler.sendEmptyMessageDelayed(100,1000);
2、发送带值的消息或延时执行:
Message message = handler.obtainMessage();
message.what = 100;
message.obj = new Object();
mHandler.sendMessage(message);
//第一个参数message 第二个参数间隔时间毫秒值
mHandler.sendMessageDelayed(message,1000);
handler移除发送的消息:
在页面关闭时记得调用下面方法移除所有消息和监听,以防页面关闭了还有一些延迟操作未执行mHandler.removeCallbacksAndMessages(null);
移除指定what对应的消息
mHandler.removeMessages(int what);
传null 所有的消息和监听都会被移除
mHandler.removeCallbacksAndMessages(null);
Handler原理解析
handler实现主要涉及以下几个类:
Handler:消息处理者,负责向消息池中发送消息 (Handler.enqueueMessage) 和处理消息 (Handler.handleMessage) 。
Message:消息,产生的消息和生成的消息。
MessageQueue:消息队列,主要功能是向消息池投递信息 (MessageQueue.enqueueMessage) 和取走消息池的信息 (MessageQueue.next) 。
Looper: 死循环执行 (Looper.loop) ,检测是否有待处理的消息,然后按分发机制将消息分发给目标处理者。
Handler
查看handler的源码会发现handler有以下构造函数:
public Handler()
public Handler(Callback callback)
public Handler(Looper looper)
public Handler(Looper looper, Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async)
handler主要实现发消息和处理接收消息,查看源码可以发现发消息无论执行那个方法最后都是执行sendMessageAtTime();
消息队列MessageQueue若为空会直接报错,不为空就会执行enqueueMessage();根据消息,延迟时间去消息队列查询消息
查看源码是细心点会看到如下代码,那SystemClock.uptimeMillis()是什么呢?它显示的是“系统启动到现在的毫秒数,不包含休眠时间。”
顺便看看其他获取时间的方法:
System.currentTimeMillis() // 从1970年1月1日 UTC到现在的毫秒数;
SystemClock.currentThreadTimeMillis();//当前线程运行的毫秒数。
SystemClock.uptimeMillis() // 从开机到现在的毫秒数(手机睡眠的时间不包括在内);
SystemClock.elapsedRealtime();//系统启动到现在的毫秒数,包含休眠时间。
Looper
Looper在消息机制里扮演着消息循环的角色,它不停的从消息队列里查看是否有新消息,如果有,则立即处理新消息,没有则一直阻塞在那里。
直接看两个片段的源代码:
从图可以看出,Looper初始化调用prepare方法,一个线程只能有一个looper,当此线程已有一个looper,在调用初始化时会抛出一个"Only one Looper may be created per thread"异常。
从图看到是一个死循环的,looper不停的从消息队列里查看是否有新消息,如果有,则立即处理新消息,没有就会跳出循环。
MessageQueue
MessageQueue消息队列,通过单向链表的数据结构存储消息或者删除消息,主要作用就是:插入和读取消息,每一次读取消息其实就是删除操作,主要的两个方法是enqueueMessage和next。直接看源码:主要看什么情况抛什么异常和大致执行逻辑
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Message
Message相对简单,就是消息类,它实现了Parcelable序列化。
使用时尽量使用obtain方法获取Message对象,不要使用new的方法,那我们看看obtain方法做了什么操作呢:
从消息池中分配消息对象,避免重新创建新对象消耗更多的内存资源,除非消息池没有消息对象才会去创建新的对象。
ThreadLocal
handler为什么会用到ThreadLocal呢,ThreadLocal是在looper时用到的,不知道你有没有发现。
ThreadLocal有以下特性:
1、是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据。
2、只有在指定的线程里才能获取到存储的数据,对于其他线程来说是获取不到的。
而我们再说looper时说了,一个线程只能有一个looper对象,已经有looper了再调用初始化时会抛出一个"Only one Looper may be created per thread"异常。这个时候就可以很方便的在不同的线程中通过ThreadLocal对Looper进行存取。
总结
handler机制就是handler将message对象发送到Looper的MessageQueue消息队列中,然后由Looper的loop方法轮询读取Message,然后调用Message的target传递给Handler的dispatchMessage()方法,将该消息回调到handleMessage方法中,执行更新操作。