Android ViewRootImpl
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android ViewRootImpl相关的知识,希望对你有一定的参考价值。
参考技术A 本文主要分析两个问题:1、为什么View 的绘制流程是从 ViewRootImpl 的performTraversals()方法开始的?
2、View 的invalidate方法是怎么触发到ViewRootImpl 的performTraversals()方法的。
在阅读本文前,最好先了解window的添加过程,android消息处理机制 和 View 的绘制流程。推荐先阅读以下文章:
Android Window和WindowManager
Android-消息机制
Android View 的绘制流程
android 源码注释的意思是:ViewRootImpl是视图层次结构的顶部,实现 View 和 WindowManager 之间所需的协议。是 WindowManager Global 的内部实现中重要的组成部分。
View 的绘制流程是从 ViewRootImpl 的performTraversals()方法开始的,那到底是哪里调用了performTraversals()方法呢,下面我们分析一下:
1.私有属性的performTraversals()方法肯定是在内部调用起来的,经过搜索找到是doTraversal()方法调用了。
2.接着找到了,调用了doTraversal() 的TraversalRunnable 类
3.内部只有一个地方实例化了TraversalRunnable 的实例mTraversalRunnable ,查到到两个方法内都调用了mTraversalRunnable ,明显 scheduleTraversals 是主动触发这个 Runnable 。这就表明调用了scheduleTraversals ()函数的地方都主动触发了view的刷新。
4.接着我们看一下 mChoreographer.postCallback 做了什么
可以看到,最后后走进了scheduleVsyncLocked()方法内。
5.mDisplayEventReceiver 的类 是 FrameDisplayEventReceiver,继承自
DisplayEventReceiver 。
最后走到这里就没了,那么这个方法是做了什么呢,这个方法的注释是这个意思:安排在下一个显示帧开始时传送单个垂直同步脉冲。意思就是,调用了这个方法可以收到系统传送过来的垂直同步脉冲信号。Android系统每隔16ms就会发送一个VSYNC信号(VSYNC:vertical synchronization 垂直同步,帧同步),触发对UI进行渲染。这个垂直同步信对于应用来说了,只有了订阅了监听,才能收到。而且是订阅一次,收到一次。
6.既然是在这个类里面订阅垂直同步信号的,那回调也应该在这里。于是找到了以下方法。
native code 调用到 onVsync,这个方法的注释解释如下:当接收到垂直同步脉冲时调用。接收者应该渲染一个帧,然后调用 @link scheduleVsync 来安排下一个垂直同步脉冲。
这个方法的具体实现在前面分析到的FrameDisplayEventReceiver 类里面。
这里可以看到,其实mHandler就是当前主线程的handler,当接收到onVsync信号的时候,将自己封装到Message中,等到Looper处理,最后Looper处理消息的时候就会调用run方法,这里是Handler的机制,不做解释。
7.最后,如下图调用所示,最终从mCallbackQueues取回之前添加的任务再执行run方法,也就是TraservalRunnable的run方法。
总结上面的分析,调用流程如下图所示如下:
上面我们分析到只要调用了ViewRootImpl 的scheduleTraversals ()方法,最终就能调用了ViewRootImpl 的performTraversals()来开始绘制。那肯定是我们常调用的view刷新的接口,经过一系列的方法调用,最终调用了ViewRootImpl 的scheduleTraversals ()方法。下面我们分析一下常用的View 的 invalidate()接口是怎么调用到了ViewRootImpl 的scheduleTraversals ()方法。
可以看出,invalidate有多个重载方法,但最终都会调用invalidateInternal方法,在这个方法内部,进行了一系列的判断,判断View是否需要重绘,接着为该View设置标记位,然后把需要重绘的区域传递给父容器,即调用父容器的invalidateChild方法。
接着我们看ViewGroup#invalidateChild:
由于不断向上调用父容器的方法,到最后会调用到ViewRootImpl的invalidateChildInParent方法,我们来看看它的源码,ViewRootImpl#invalidateChildInParent:
最后调用了scheduleTraversals方法,触发View的工作流程。至此,我们已经完整地分析了一次调用View 的 invalidate()方法到触发ViewRootImpl 的scheduleTraversals()方法。
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@e48ad
问题:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@e48ad73 -- permission denied for window type 2010
详细:
解决方案:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) //6.0
mLp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;// 系统提示类型,重要
else
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;// 系统提示类型,重要
以上是关于Android ViewRootImpl的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )