Android非属性动画循环播放引起Activity的onDestroy()回调延时

404 阅读2分钟

比如在补间动画的startAnimation()方法中会执行view.invalidate()进行重绘,其中会调用到ViewRootImpl.scheduleTraversals(),它会在消息队列中设置同步屏障,阻塞后面的同步消息执行。

使用帧动画的话,它的start()中会调用到View类实现的scheduleDrawable()执行重绘,其中会调用Choreographer.postCallbackDelayedInternal()往消息队列发送延时消息。

两种非属性动画刷新频繁地循环播放,并在Activity的onPause()没有进行停止的话,很容易造成消息队列的消息处理阻塞,而Activity的onDestroy()调用一般依赖于IdleHander完成,如果消息队列一直有待处理message,IdleHandler无法执行就会引起onDestroy()延时。

最大延时时间与AMS中的IDLE_TIMEOUT值相关,在AMS唤醒下一Activity过程中ActivityRecord.completeResumeLocked()会发送一个延时IDLE_TIMEOUT时间的Message,确保正常流程走不通的情况下也能销毁activity。当IDLE_TIMEOUT时间到达后,会执行ActivityStack.destroyActivityLocked()发起IPC,通知App销毁Activity,然后App调用ActivityThread.handleDestroyActivity()会执行onDestroy()

而属性动画的start()会调用AnimationHandler.addAnimationFrameCallback()将当前的AnimationFrameCallback对象添加到mAnimationCallbacks中,若此前mAnimationCallbacks集合大小为零,会执行MyFrameCallbackProvider.postFrameCallback()将一个FrameCallback对象放入Choreograher的待处理队列里,并向底层注册监听下一个屏幕刷新信号事件。当接收到屏幕刷新信号,Choreograher的待处理队列中的FrameCallback对象的doFrame()会被回调,对当前动画进行处理,然后根据mAnimationCallbacks集合大小是否为零判定是否继续向下层注册监听屏幕刷新信号事件,在此过程中,属性动画一般不会直接造成消息队列的阻塞,导致onDestroy()延时。

但如果属性动画比较复杂并循环播放,比如多个画面变化较大属性动画复合循环播放,也有可能引起延时问题,因为属性动画的绘制也是通过ViewRootImpl.scheduleTraversals()

参照:

www.jianshu.com/p/30cfa00fc…

blog.csdn.net/kg_2012/art…

blog.csdn.net/weixin_3192…

www.jianshu.com/p/46f48f1b9…

www.ktanx.com/blog/p/4751

blog.csdn.net/suyimin2010…

www.jianshu.com/p/479b78235…