Handler实现原理解析
目录:
Handler
Handler概述:
Handler并不是专门用来更新UI界面的,只不过日常开发中,开发者用来更新UI比较多.
Handler的主要作用是:将一个任务切换到某个指定线程进行执行.
Handler的主要目的是:为了解决在子线程中无法更新UI界面的矛盾问题
Handler原理图:
主线程中为什么可以直接创建Hanlder:
在非主线程中创建Handler的时候需要先调用Looper.prepare();创建Looper对象以及完成消息队列的初始化,然 后创建Handler对象,最后,调用Looper.loop();开启消息循环;
而在主线程中,App的入口,ActivityThread.main方法中:
public static void main(String[] args) {
// 不相干代码
......
// 1.调用Looper.prepareMainLooper,其实也就是调用的Looper.loop,初始化Looper、MessageQueue等
Looper.prepareMainLooper();
// 2.创建ActivityThread的同时,初始化了成员变量Handler mH
ActivityThread thread = new ActivityThread();
thread.attach(false);
//
if (sMainThreadHandler == null) {
// 把创建的Handler mH赋值给sMainThreadHandler
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 3.调用Looper.loop()方法,开启死循环,从MessageQueue中不断取出Message来处理
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
主线程不需要手动调用,是因为系统在启动App时,就帮我们调用了
Handler使用的两种方式:
**一:post方式**Handler mHandler = new Handler();
mHandler.post(new Runnable() {
@Override
public void run() { }
});
二:Message方式
//主线程中创建Handler
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理返回的消息
}
};
//---------------------------------------------
//在子线程总调用Handler发送消息
Message msg = Message.obtain();
msg.what = MSG_SUB_TO_MAIN;
msg.obj = "这是一个来自子线程的消息";
// 2.发送消息
mHandler.sendMessage(msg);
Handler中构造函数
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
...
}
- 在创建Handler对象的时候,在构造函数中首先会初始化Looper对象并获取其中的MessageQueue消息队列对象;
- 当创建Handler对象的线程中没有初始化Looper对象的时候就会导致抛出异常
post,Message调用的原理
post方式调用首先会调用getPostMessage(r)方法;private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在该方法中,创建一个Message对象,将需要执行的Runable对象设定为callback
随后,post方法就和Message方法一样,都会调用sendMessageDelayed()方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
在该方法中对设定的延迟时长进行判断,随后都调用了sendMessageAtTime(方法);
public boolean sendMessageAtTime(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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 在sendMessageAtTime()获取了Looper中的MessageQueue对象
- 在enqueueMessage()中将Hnadler对象赋值给了msg.target,并且将传入的Message对象进行了enqueueMessage入队操作
Looper
Looper的构造函数
private Looper(boolean quitAllowed) {
...
mQueue = new MessageQueue(quitAllowed);
...
}
在创建的Looper的时候在Looper的构造函数中会首先初始化好一个MessageQueue用来保存需要处理的meassage,所以消息队列在looper对象进行初始化创建的时候一并创建好了.
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper创建的时候调用prepare方法,每个线程中只允许存在一个Looper,所以在重复创建会导致异常,当首次创建完成后,会将该Looper对象存储到sThreadLocal中,并且在构造函数中完成队列MessageQueue的初始化
开启Looper循环的loop()
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...省略部分代码
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...省略部分代码
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...省略部分代码
msg.recycleUnchecked();
}
}
-
在Looper中执行循环的是loop方法,在方法中是一个无限循环,其中就调用到了MessageQueue中的next方法,而next方法也是一个无效循环的方法,在没有消息的时候就处于阻塞状态,在有消息的时候就对消息进行返回并将该条消息从消息队列中移除;所以综合来说,Looper中的无线循环通过MessageQueue的next方法获取到了消息.
-
唯一退出循环的判断条件是next为null,在什么情况下next会返回null呢?当调用Looper的quit方法时,会调用MessageQueue中的quit或者quitSaffely,两个退出方法二者的区别是一个立即退出,一个是将当前队列状态修改为退出状态,等任务执行完成之后退出,当消息队列被标记为退出状态时,next会返回null;
-
在获取消息队列中的message对象后,会通过msg.target获取到Handler对象,去调用Handler中的dispatchMessage(msg);方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
在dispatchMessage方法中,首先会判断Runnable对象是否为空,假如我通过post方法封装了需要执行的Runnable,那么在此处就会通过handleCallback()进行执行;而不论有没有,最终都会再执行Handler中的handleMessage()方法
MessgaeQueue工作原理:
MeassgaeQueue翻译的为消息队列,但它实质上并不是一个消息队列,它的内部是一个单链表的数据结构用来存储数据,但其并不对数据进行处理.
MessgaeQueue主要用到的有两个方法enqueueMessage和next,
enqueueMessage主要用来存储数据,想单链表中插入一条数据,next则是向链表中取出一条数据,并从队列中删除,需要说明的一点是,在next内部是一个无线循环,当没有消息的时候就处于阻塞状态,在有消息的情况下就会进行返回并将该条消息从队列中移除.