怎么获取页面加载完成的最佳时机?
2019-03-07 本文已影响0人
wan7451
Android 开发页面的时候,一般的流程都是先加载页面,等页面加载完成后再执行其他后续操作。而获取页面加载完成的时机,有各种各样的方式。比如:
- 使用Handler延迟200毫秒加载
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//加载数据
}
},200);
- 监听全局布局加载
View root = findViewById(R.id.container);
root.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//加载数据
root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
- view的Post方法
view.post(new Runnable() {
@Override
public void run() {
}
});
今天无意中发现一个骚操作,使用 IdleHandler 获取页面加载完成的时机,代码很简单
@Override
protected void onResume() {
super.onResume();
getMainLooper().myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
//加载完成
//false 执行一次,true 执行多次
return false;
}
});
}
IdleHandler 即是懒惰的Handler。IdleHandler的方法执行时机是在MessageQueue中没有Message时执行,也就是主线程空闲的时候执行。熟悉Handler、Looper的同学一看源码就清楚了。
public static void loop() {
//....
for (;;) {
//....
Message msg = queue.next(); // might block
//....
}
}
在Looper的loop()方法中,会从消息队列中取出msg,然后再执行 msg.target.dispatchMessage(msg)。接下来重点看下MessageQueue.next()方法。
Message next() {
//...
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
从上面的代码以及注释中就能看出,当Message为空的时候,系统就会执行IdleHandler 数组中的queueIdle()方法。所以说IdleHandler是在空闲的时候执行逻辑的。
那么在为什么说onResume()方法中 queueIdle() 是在布局加载完成调用的,请参考这个文章。
https://mp.weixin.qq.com/s/KpeBqIEYeOzt_frANoGuSg