addIdleHandler代码不执行

本文介绍了在Android应用启动速度优化中,IdleHandler未执行导致的问题及解决方案。通过添加日志打印定位到频繁更新页面的原因,发现是自动滚动的RecyclerView和不必要的布局监听导致。通过优化这两部分代码,成功解决了问题,使得IdleHandler能够正常执行,从而恢复启动速度优化的效果。
摘要由CSDN通过智能技术生成

关于android启动速度的优化,相信大家都会用到IdleHandler去处理一些空闲任务,如下

 Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
            	//处理空闲任务
              return false;
            }
        });

既然是想提高启动速度,那么IdleHandler基本上都用在MainActivity的onCreate中,此时进入到app主页了,等待空闲时去提前执行一些非必要的初始化信息,或者进行预加载。

项目中之前版本的功能都是正常的,这段代码也能执行到,突然新版本这里面代码始终走不到,那么意味着里面初始化信息都将失效,启动速度优化也功亏一篑,好不容易做的功能,又被打回原形。

其实这个空闲handler代码不执行,根本原因只有一个,就是它不空闲并且很忙,没空处理你的空闲任务,那么为什么他会很忙呢?肯定是有地方在不停更新页面。虽然问题基本上可以定位在新老版本开发的需求中间,但是那么多代码,怎么去定位这个问题呢?

别急!别急!往下看!

我们知道整个app都是在loop中的死循环中的

for (;;) {
    Message msg = queue.next(); 
    if (msg == null) {
        return;
    }
    final Printer logging = me.mLogging;
    if (logging != null) {
        logging.println(">>>>> Dispatching to " + msg.target + " " +
                msg.callback + ": " + msg.what);
    }
    //省略代码。。。
    if (logging != null) {
        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    }
  }

方法中已经提供了log的打印,而且是成对出现的,开始和结束都会打印,由此我们可以尝试打印handler处理的日志,到底是谁在一直更新。

我们在addIdleHandler之前添加log:

Looper.myLooper().setMessageLogging(new LogPrinter(Log.ERROR, "Ajiang"));

这样上面的死循环代码的logging就不为空,打印如下所示:

E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} android.view.ViewRootImpl$SendWindowContentChangedAccessibilityEvent@d7faa81: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} android.view.ViewRootImpl$SendWindowContentChangedAccessibilityEvent@d7faa81
E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} android.view.View$SendViewScrolledAccessibilityEvent@363299b: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} android.view.View$SendViewScrolledAccessibilityEvent@363299b
        E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2
        E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {90e4ced} null: 2
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {90e4ced} null
        E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2
        E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {90e4ced} android.view.Choreographer$FrameDisplayEventReceiver@2d52722
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {301f6b1} com.xxx.xxx.recyclerview.AutoPollRecyclerView$AutoPollTask@613a6b2

可以很明显的发现日志一直在循环打印,而且速度很快,很容易定位到AutoPollRecyclerView这个类有问题,于是查看发现这是个自动滚动的Recyclerview,还没到这个页面对应的tab就已经开始滚动了,所以这肯定是有问题的,改成切换到对应页面再去滚动。

本以为大功告成,于是重新跑遍代码,发现日志仍然再循环滚动。

E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@8020ce7: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@8020ce7
        E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {a4b9c07} android.view.Choreographer$FrameDisplayEventReceiver@25c134: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {a4b9c07} android.view.Choreographer$FrameDisplayEventReceiver@25c134
        E/Ajiang: >>>>> Dispatching to Handler (android.os.Handler) {e88c10f} null: 2
        E/Ajiang: <<<<< Finished to Handler (android.os.Handler) {e88c10f} null
        E/Ajiang: >>>>> Dispatching to Handler (android.os.Handler) {51748c6} null: 1
        E/Ajiang: <<<<< Finished to Handler (android.os.Handler) {51748c6} null
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@a781094: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@a781094
E/Ajiang: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {a4b9c07} android.view.Choreographer$FrameDisplayEventReceiver@25c134: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {a4b9c07} android.view.Choreographer$FrameDisplayEventReceiver@25c134
        E/Ajiang: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@a4573d: 0
        E/Ajiang: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {f0cee21} com.xxx.xxx.ui.adapter.recommend.HomeChallengeAdapter$7$1@a4573d

好家伙,竟然还有一处,定位代码

ll_challenge_content.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        ll_challenge_content.post(new Runnable() {
            public void run() {
                ll_challenge_content.requestLayout();
                bgParams.height = ll_challenge_content.getMeasuredHeight() + ScreenUtils.dp2px(55);
            }
        });

    }
});

这一直监听,一直刷,这不得忙到死么。看了下代码逻辑,其实这个地方完全没必要做监听的,后续发现这段代码的确是可以删掉的,就算不能删的话,可以换种思路做,要么加标记位,避免死循环,适当移除监听。

最后跑一遍代码,终于没有死循环的日志了,也能成功进入IdleHandler的执行代码中,启动优化也可以恢复正常了,叹了口气!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值