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 用户权限 )

android 21 是啥版本

Android逆向-Android基础逆向(2-2)

【Android笔记】android Toast

图解Android - Android核心机制

Android游戏开发大全的目录