前面写过一篇idleHandler不执行,后续发现前面的技术不支持解决现在遇到的问题,故有了第二篇文章
首先得知道这个IdleHandler回调不执行,会有啥危害?
- onStop、onDestroy不能及时执行,基本都在十秒左右(系统兜底),导致内存泄漏;
- 启动优化HomeActivity中空闲不执行,导致一些初始化代码不能正常执行,导致后续问题。
下面列举那些场景下会出现这种问题:
-
内存泄漏场景 启动一个透明主题的activity,当前页面有个自定义view带动画,不可见时才会暂停, 动画执行导致idlehandler不执行,mactivitys没有赋值null,持有引用,也就会导致onStop、onDestroy无法正常执行
-
idlehandler 空闲线程不执行,切换到其他tab才会去执行(会关闭),loop中打印日志,发现挑战区有个自动滚动的列表,10ms就重新scrollto一次,一直绘制,没有空闲线程
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,LOG_TAG));
日志
<<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {c5afe55} cn.emagsoftware.gamehall.widget.recyclerview.AutoPollRecyclerView$AutoPollTask@e844865
>>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {c5afe55} com.migugame.home_module.ui.adapter.recommend.HomeChallengeAdapter$7$1@dcfb12e: 0
-
升级到androidx后,发现不能通过上面的方式查看日志去定位,因为后台一直在打印编舞者信息,走的系统渲染看不出是谁在调用
E >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6: 0 E <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6 E >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6: 0 E <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6 E >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {fe83801} null: 2 E <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {fe83801} null E >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6: 0 E <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6 E >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6: 0 E <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {fe83801} android.view.Choreographer$FrameDisplayEventReceiver@8b656a6
网上查找一番后发现是因为viewpager无限绘制https://www.jianshu.com/p/25c139e9666a导致的,触发viewpager无限绘制场景:
- 升级到androidx
- 使用了全屏(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
- 页面中有ViewPager
- ViewPager中有CollapsingToolbarLayout
- 根布局没有使用fitsSystemWindows
下面通过Perfetto和断点去分析这个问题。
未修改:
循环绘制dispatchApplyInsets,作为突破口,然后配合断点
解决方案如上文章中所说:
1.viewpager下的有问题布局中的根增加
android:fitsSystemWindows="true"
2.重写viewpager,进行消费
return applied.replaceSystemWindowInsets(res.left,res.top,res.right,res.bottom).consumeSystemWindowInsets();
解决这个大问题后,发现idleHandler可以正常回调了!大功告成!后续验证又发现如下小问题,属于优化:
通过Perfetto查看:进入到活动列表后,有动画仍然在执行,但是页面上没有动画知道是动画引起的,在对应源码位置断点(只能断方法,查看左侧调用链),定位出资源id即可查找出问题所在。