如何判断当前线程是否为主线程?
public static boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
如何创建异步Handler?
异步Handler发送的消息为异步消息,不受同步屏障(synchronization barriers)的约束。
public static Handler createAsync(@NonNull Looper looper) {
if (Build.VERSION.SDK_INT >= 28) {
return Handler.createAsync(looper);
}
if (Build.VERSION.SDK_INT >= 16) {
try {
return Handler.class.getDeclaredConstructor(Looper.class, Handler.Callback.class, boolean.class)
.newInstance(looper, null, true);
} catch (IllegalAccessException ignored) {
} catch (InstantiationException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (InvocationTargetException e) {
return new Handler(looper);
}
}
return new Handler(looper);
}
Message的复用机制
复用机制通过Message.obtain()
方法来实现,它会从一个消息池中获取可用的Message对象,而不是每次都创建新的对象。
// Handler.java
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
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();
}
那么消息是什么时候被添加到消息池sPool中的呢?查看Message类的源码,找到一个recycle
方法,此方法又调用了recycleUnchecked
方法,最终在recycleUnchecked
方法里消息被回收添加到消息池中。
// Handler.java
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
问题又来了,那recycle
方法或recycleUnchecked
方法什么被调用呢?全局搜索一下,在Looper类里找到loopOnce
方法有调用Message的recycleUnchecked
方法,代码如下:
//Looper.java
@SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
......
msg.recycleUnchecked();
return true;
}
什么是IdleHandler?
IdleHandler是一个接口,可用于执行一些在UI线程空闲时执行的任务。当Looper处于空闲状态时,系统会调用IdleHandler的回调方法,以执行一些额外的任务,如数据加载、后台计算等。
// MessageQueue.java
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
如我们想在主界面显示完成后做一些事情,可以使用以下代码:
Looper.myQueue().addIdleHandler(() -> {
//加载数据等
......
return false;
});