Android源码分析之Handler消息机制
前言
随着Android的不断发展,越来越多的开发者开始对源码开始研究,Handler作为子线程的重要成员,下面让我们一起进行源码学习。
一、Handler是什么?
在Android开发中,Handler主要被用来进行耗时操作,消息处理等,大家都知道在主线程中进行耗时操作或者IO读写,会引发ANR异常,所以Android引入Handler来开启子线程进行耗时操作和IO读写,等处理完,Handler将处理结果返回给主线程进行展示。
二、Handler包括哪些部分
1.Looper
在Handler的构造器中:
public Handler(@Nullable Callback callback, boolean async) {
xxxxx
xxxxx
省略代码.....
mLooper = Looper.myLooper(); //在创建Handler时默认获取一个mLooper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()"); //Looper不能为空,否则报运行时异常
}
mQueue = mLooper.mQueue;//通过mLooper获取一个消息队列mQueue
mCallback = callback;
mAsynchronous = async;
}
由此可见,当我们创建Handler的时候,Handler已经为我们准备好了一个不为空的Looper。
进入到Looper中。在Looper的构造器中,初始化了MessageQueue,并获取当前的线程。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //消息队列
mThread = Thread.currentThread(); //获取当前线程
}
在系统调用Looper的prepare方法时,先判断sThreadLocal中是否存在looper,如果存在即报运行时异常,threadLocal通过存储当前线程里的looper,可以实现在不同线程中提供不同的数据,而互不干扰。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
通过sThreadLocal来获取当前线程的looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
2.Message
Message是信息的主要载体,通过Message来传递不同的数据。 通过源码得知,Message实现来Parcelable序列化接口。
public final class Message implements Parcelable
public static final Object sPoolSync = new Object(); //同步对象锁
private static Message sPool; //消息池
从全局池返回一个新的Message实例。使我们在许多情况下避免分配新对象
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Message通过target来保存当前创建的handler对象,
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
3.MessageQueue
MessageQueue 消息队列,用来存储信息。
总结
Handler消息机制需要MessageQueue和Looper支撑,Handler中Looper在初始化时会创建消息队列和获取当前线程。Looper通过ThreadLocal存储,确保可以为不同的线程提供不同的数据信息。