怎么获取页面加载完成的最佳时机?

2019-03-07  本文已影响0人  wan7451

Android 开发页面的时候,一般的流程都是先加载页面,等页面加载完成后再执行其他后续操作。而获取页面加载完成的时机,有各种各样的方式。比如:

  1. 使用Handler延迟200毫秒加载
new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
    //加载数据
  }
},200);
  1. 监听全局布局加载
View root = findViewById(R.id.container);
root.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
        //加载数据
        root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
});
  1. 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

上一篇下一篇

猜你喜欢

热点阅读