Handler是Android开发必须使用到的技术,使用呢也很简单,在主线程重写Handler的handleMessage方法,在子线程中通过handler的sendMessage()方法发送消息。
通过这张图可以很好的理解Handler机制,其中有几个角色ActivityThread、Handler、Message、MessageQuene、Looper,首先对这些角色做一下简单介绍:
ActivityThread:程序的启动入口,这个类也就是我们平常所说的主线程(UI线程),更新UI的操作必须在主线程中进行
Handler:字面意思就是操控者,在子线程中要通过handler的sendMessage()方法发送消息到MessageQuene中,并且通过重写Handler的handleMessage()方法处理消息。在Handler中持有MessageQuene和Looper的对象
MessageQuene:消息队列,就是存放Message的一个队列,对handler发送过来的消息进行插入,Looper从这个队列中循环取出消息
Message:也就是消息,在Message中定义了几个字段分别表示不同的信息。
ActivityThread.main()
public static void main(String[] args) {
//......
//只贴出相关代码
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
//.....
}
main()方法就是程序的入口,通过查看ActivityThread的main()方法,可以发现这里调用了Lopper类的prepareMainLooper()方法和loop()方法,接下来在看Looper类
Looper
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
在Looper中包含了这几个字段
ThreadLocal:每个线程中都有一个ThreadLocal,这里用来保存当前线程的Looper对象
MessageQuene:消息队列
Thread:当前的线程对象
接下来在看prepareMainLooper()和loop()方法
public static void prepareMainLooper() {
prepare(false);//这里调用了prepare方法
synchronized (Looper.class) {
if (sMainLooper != null) {//这里判断sMainLooper 是否为空
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();//为空则调用myLooper()方法从ThreadLocal中取出Looper对象
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
//可以发现,prepare方法只能调用一次,也就是一个线程中只能有一个Looper,否则就会抛出异常
}
sThreadLocal.set(new Looper(quitAllowed));//ThreadLocal中如果没有Looper对象,则new一个
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//取出Looper对象
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
//下面是loopOnce中的方法
//从mQuene中循环取出消息(mQuene就是上面所说的MessageQuene这个字段)
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
//通过Message的target分发消息(就是发送这条消息的Handler)
msg.target.dispatchMessage(msg);
//这里清空msg里面的表示、参数等清空
msg.recycleUnchecked();
通过上面的分析我们发现,loop方法中会取出内部的消息序列器,并且迭代消息,根据msg的target属性进行分发操作,但是现在有一个问题,MessageQuene中的消息是从哪里来的?这个时候就到了我们的Handler了。
Handler
首先还是先看Handler的字段
final Looper mLooper;//通过Looper传递MessageQuene
final MessageQueue mQueue;//在Handler中并没有实例化,而是指向了Looper的MessageQuene
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
接下来在看Handler的构造函数
public Handler(@Nullable Callback callback, boolean async) {
//.............
mLooper = Looper.myLooper();//从当前线程的ThreadLocal中取出Looper对象
if (mLooper == null) {
/*
*注意:如果是在主线程中的话,系统默认已经调用了Looper.prepare()方法,但是在子线程中创建
*时我们要手动调用prepare()方法,否则就会抛出如下异常,也可以在创建Handler对象时传入当前
*线程的Looper对象
*/
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//指向Looper的MessageQuene
mCallback = callback;
mAsynchronous = async;
}
接下来在看Handler是如何发送消息的,其实不论我们调用sendMessage()还是其他方法最终都会走到sendMessageAtTime()方法中
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
sendMessageAtTime()方法接收两个参数,一个Message对象,和一个时间参数,表示发送消息的时间(这个值为系统当前的时间+延时时间,比如调用sendMessageDelayed方法时),然后将这两个参数都传入了enqueueMessage方法中,在进入这个方法看一下
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
//将msg的Target属性指定为this,也就是当前Handler,也就对应了Looper中的loop方法
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
//通过MessageQuene将msg进行入队操作,到这里就知道MessageQuene中的消息是从哪里来的了
}
总结:
- 一个线程中只能存在一个Looper对象,但是可以有多个Handler
- 一个Looper可以绑定多个Handler,反之一个Handler只能绑定一个Looper(也就是当前线程的Looper)
创建Handler之后,通过Handler发送Message,在Handler内部将Message存储到MessageQuene中,然后通过Looper从MessageQuene中循环取出Message,然后在通过Handler的handleMessage()方法处理Message,就可以完成UI的更新
个人理解哦!!!!