Handler是什么
- Handler是系统提供的用于线程切换的类
- Handler的主要作用是实现异步的消息处理,跟web开发的ajax有异曲同工之妙。
Handler、Looper、MessageQueue关系
- Handler中持有Looper
Handler创建的时候需要传入一个Looper,或者从ThreadLocal中取当前的Looper - Looper中持有MessageQueue
在创建Looper的时候,MessageQueue对象也被创建好了,MessageQueue的数据结构其实并不是队列,这里采用了单链表的形式,因为单链表在插入和删除时,比队列有优势。
//如果没有传参数,会从ThreadLocal中取当前线程的Looper,取失败则抛出异常
private val handler = Handler()
//或者可以手动指定传入一个Looper,例如传入主线程的Looper
private val handler = Handler(Looper.getMainLooper())
Handler工作流程和原理
- Handler切换线程原理
Handler在子线程中发送的消息,实际上就是在MessageQueue(绑定了主线程的Looper)中添加一条Message,通过Looper中的消息循环取得Message交给Handler处理。 - Handler发送消息
Handler.post最终也是调用的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);
}
- Handler处理消息
handleMessage是一个空方法,我们通常重写该方法来处理消息
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
子线程中创建Handler
- 通常我们创建Handler都是在主线程的,如果要在子线程中创建Handler需要注意以下问题
- 在非UI线程中,直接new Handler()是不可以的,因为Handler中必须要持有一个Looper,默认情况下,Android中新开启的线程,是没有开启消息循环的,如果要在线程中使用Handler,那么就要先调用Looper.prepare,主线程中,自动创建了Looper对象
- Handler中必须持有一个Looper
这个Looper如果没有传入,则会从ThreadLocal中取
public Handler(@Nullable Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- 子线程中创建Handler引发的异常
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-3,5,main] that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:207)
at android.os.Handler.<init>(Handler.java:119)
- Looper.prepare中创建了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));
}
- 先调用Looper.prepare再创建Handler
private fun handlerTest() {
var handler: Handler?
Thread {
Looper.prepare()
handler = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
}
}
}.start()
}
ThreadLocal对象
-
ThreadLocal概念:线程局部变量,是一种多线程间并发访问变量的解决方案。与其synchronized等加锁的方式不同,ThreadLocal完全不提供锁,而使用以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全。
-
从性能上说,ThreadLocal不具有绝对的优势,在并发不是很高的时候,加锁的性能会更好,但作为一套与锁完全无关的线程安全解决方案,在高并发量或者竞争激烈的场景,使用ThreadLocal可以在一定程度上减少锁竞争。
-
通过ThreadLocal来创建线程的内部变量。只创建一个Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
- Activity中有一个ActivityThread,其中有main函数,java程序的入口,里面有一个Looper。
public static void main(String[] args) {
Environment.initForCurrentUser();
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
- Looper.loop中的死循环会判断queue中的Message是否为空,如果为空则会阻塞等待新消息。该Looper不会退出,如果退出了就会执行ActivityThread中的throw new RuntimeException(“Main thread loop unexpectedly exited”);并且退出页面。
public static void loop() {
for (;;) {
//queue.next中阻塞
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
...
...
}
}
- Message msg = queue.next();
MessageQueue中的next方法中会阻塞等待消息
// MessageQueue中的next方法
Message next() {
final long ptr = mPtr;
if (ptr == 0) { //当消息循环已经退出,则直接返回
return null;
}
int pendingIdleHandlerCount = -1; // 循环迭代的首次为-1
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//阻塞操作,当等待nextPollTimeoutMillis时长,或者消息队列被唤醒,都会返回
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//当消息的Handler为空时,则查询异步消息
if (msg != null && msg.target == null) {
//当查询到异步消息,则立刻退出循环
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 获取一条消息,并返回
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
//设置消息的使用状态,即flags |= FLAG_IN_USE
msg.markInUse();
return msg; //成功地获取MessageQueue中的下一条即将要执行的消息
}
} else {
//没有消息
nextPollTimeoutMillis = -1;
}
//消息正在退出,返回null
if (mQuitting) {
dispose();
return null;
}
//当消息队列为空,或者是消息队列的第一个消息时
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//没有idle handlers 需要运行,则循环并等待。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//只有第一次循环时,会运行idle handlers,执行完成后,重置pendingIdleHandlerCount为0.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; //去掉handler的引用
boolean keep = false;
try {
keep = idler.queueIdle(); //idle时执行的方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置idle handler个数为0,以保证不会再次重复运行
pendingIdleHandlerCount = 0;
//当调用一个空闲handler时,一个新message能够被分发,因此无需等待可以直接查询pending message.
nextPollTimeoutMillis = 0;
}
}
Handler线程切换原理
- Handler的工作流程是自己发,自己处理
- 那么主线程中的Handler发送的消息,也是在主线程中处理的,所以可以创建一个主线程的 new HandlerMain(Looper.getMainLooper());
- 如果要创建子线程的Handler,则需要先Looper.prepare()创建子线程的Looper
package com.vision.myhandler;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
/**
* 提供一个 runOnUiThread 的方式,可以在任何线程中调用
*/
public final class HandlerMain extends Handler {
private static class Holder {
private static final HandlerMain INSTANCE = new HandlerMain(Looper.getMainLooper());
}
private HandlerMain(Looper looper) {
super(looper);
}
public static HandlerMain getInstance() {
return Holder.INSTANCE;
}
public static void runOnUiThread(Runnable runnable) {
if (Looper.getMainLooper().equals(Looper.myLooper())) {
runnable.run();
} else {
getInstance().post(runnable);
}
}
}
- Handler处理runnable
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
//先判断runnable是否为null,处理runnable
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//处理runnable,调用runnable.run()执行其中的内容
private static void handleCallback(Message message) {
message.callback.run();
}
Looper源码
public final class Looper {
private static final String TAG = "Looper";
//消息队列
final MessageQueue mQueue;
//当前创建的所在线程
final Thread mThread;
private Printer mLogging;
private long mTraceTag;
private long mSlowDispatchThresholdMs;
private long mSlowDeliveryThresholdMs;
//这是第一个开始使用的地方
public static void prepare() {
prepare(true);
}
//主要创建了Looper对象,MessageQueue对象,指定了创建的线程
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));
}
//这个可以和下面的getMainLooper()结合一块看,看名字是指定在主线程的Looper,但是这里从哪能看出他是应用在主线程呢;这里说明一下,prepareMainLooper()是应用在了三个地方
//1、ActivityThread的main方法中,APP启动的时候
//2、Bridge的prepareThread()方法中
//3、SystemService的run()方法中
//后两个暂时不管,第一个我们一般在看源码解析的时候时长见到,一般有大神分析Activity启动这一类的
public static void prepareMainLooper() {
//主线程不能退出,主线程都退出了还玩什么
prepare(false);
synchronized (Looper.class) {
//不能二次调用
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//获取主线程上的Looper
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
//开始循环分发MessageQueue中的消息到Handler
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
//获取消息队列中的消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//然后分发消息到Handler的处理中
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//释放消息
msg.recycleUnchecked();
}
}
private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
String what, Message msg) {
final long actualTime = measureEnd - measureStart;
if (actualTime < threshold) {
return false;
}
// For slow delivery, the current message isn't really important, but log it anyway.
Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
+ Thread.currentThread().getName() + " h="
+ msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
return true;
}
//获取Looper实例
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//获取Looper绑定的MessageQueue
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
//实例化,同时实例化一个MessageQueue并获取当前Looper创建的线程
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//判断调用该api的线程是否为创建线程
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
public void setTraceTag(long traceTag) {
mTraceTag = traceTag;
}
public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
mSlowDispatchThresholdMs = slowDispatchThresholdMs;
mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
}
//退出消息栈
public void quit() {
mQueue.quit(false);
}
//安全退出消息栈
public void quitSafely() {
mQueue.quit(true);
}
//获取当前线程
public @NonNull Thread getThread() {
return mThread;
}
//获取当前MessageQueue
public @NonNull MessageQueue getQueue() {
return mQueue;
}
public void dump(@NonNull Printer pw, @NonNull String prefix) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ", null);
}
public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ", handler);
}
/** @hide */
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long looperToken = proto.start(fieldId);
proto.write(LooperProto.THREAD_NAME, mThread.getName());
proto.write(LooperProto.THREAD_ID, mThread.getId());
mQueue.writeToProto(proto, LooperProto.QUEUE);
proto.end(looperToken);
}
@Override
public String toString() {
return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
+ ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
}