ViewRoot/ViewRootImpl分析_viewrootimpl nosuchmethod-程序员宅基地

技术标签: Android 源码  

原文 Android中的ViewRootImpl类源码解析  http://blog.csdn.net/qianhaifeng2012/article/details/51737370

这篇文章是对上面文章部分内容的总结:

ViewRoot和ViewRootImpl,从字面上来看,还以为ViewRootImpl是ViewRoot的实现, 其实不是的。ViewRoot是Android2.2以前的,2.2之后就被ViewRootImpl替代了。 

ViewRootImpl的作用:

1,WindowManager和DecorView的纽带

2,绘制View,调用了performMeasure(), performLayout(), performDraw()方法,因而调用View的 measure,layout,draw方法完成view的绘制。

3,传递各种event事件,如按键,触屏等事件给View。

ViewRootImpl

ViewRootImpl是一支树结构的顶部,但是不是View, 实现了View和WindowManager的通信协议,大部分的实现细节是在WindowManagerGlobal类中的。

WindowManager

WindowManager主要有增、删、改view的 三个方法,并且这 三个方法是通过继承ViewManager获得的。并且这三个方法是由WindowManager的实现类WindowManagerImpl实现的,而WindowManagerImpl对三个方法的实现是通过调用WindowManagerGlobal的具体方法来实现的。

WindowManagerGlobal

不能直接访问Window,需要通过WindowManger访问Window,而WindowManagerImpl实现WindowManager,具体的实现里又调用了WindowManagerGlobal的 方法,比如,想添加Window,最终调用的是WindowManagerGlobal的addView方法,添加一个Window其实就是在添加一个View,Window只是一个抽象的概念。在WindowManagerGlobal中有下面几个成员变量

private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();

mViews存储的是所有Window所对应的View,mRoots存储的是所有Window所对应的ViewRootImpl,mParams存储的是所有Window所对应的布局参数,而mDyingViews存储了那些正在被删除的View对象,或者说是那些已经调用removeView方法但是还没有删除的Window对象。

 WindowManagerGlobal的addView方法:就是用来 添加Window的

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //这里都是一些参数的判断和设置,省略掉了
        ...
 
        ViewRootImpl root;
        View panelParentView = null;
 
        synchronized (mLock) {
            // Start watching for system property changes.
            ...
 
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }
 
            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            ...
            //在这里初始化ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);

            //给要添加的View设置参数
            view.setLayoutParams(wparams);

            //把要添加的View存入集合
            mViews.add(view);

            //把初始化的ViewRootImpl存入集合
            mRoots.add(root);

            mParams.add(wparams);
        }
 
        // do this last because it fires off messages to start doing things
        try {

            //从这里可以看出,真正添加View(就是添加Window)的其实就是ViewRootImpl了
            root.setView(view, wparams, panelParentView);

        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

//从 root.setView(view, wparams, panelParentView); 可以看出,真正添加View(Window)的其实就是ViewRootImpl了,而root.setView()方法中又调用了requestLayout()来完成异步刷新请求,requestLayout()又会调用performTraversals来完成View的绘制,又接着会通过IWindowSession的addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mInputChannel)方法来完成Window的添加过程,IWindowSession是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。 下面是Session中的addToDisPlay方法:

    @Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
       int viewVisibility, int displayId, Rect outContentInsets,
        InputChannel outInputChannel) {
       return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
 }

可以看出,Window的添加请求就交给WindowManagerService去处理了。addView大概一个过程如下:
WindowManager——>WindowManagerGobal——>ViewRootImpl——>Session——>WindowManagerService

在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联,可以参考一下代码,在ActvityThread中,也就是ViewRootImpl是DecorView的父元素,但是ViewRootImpl并不是View。

r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//getWindowManager这里用父类引用指向子类对象WindowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
      a.mWindowAdded = true;
      //WindowManager添加decorView
      wm.addView(decor, l);
}


 

   

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jinchen_boke/article/details/88365701

智能推荐

HDU 4044 GeoDefense(树形dp+分组背包)_acm geodefense-程序员宅基地

文章浏览阅读273次。题意:给你一棵n个结点的树,1号结点为敌人基地,叶子结点为我方基地。我们可以在任意一个结点至多修建一门大炮,每个结点有k种大炮,每种大炮有花费值和伤害值。问在给你m元的基础上,我们一定可以打败敌人的最大值。题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4044题解思路:首先这是很明显的树形dp,我们要求的是每个结点的最小攻击值中的最大值,才_acm geodefense

前端基础第四天_前端swsf-程序员宅基地

文章浏览阅读186次。经过几天的html的学习,已经有点开始慢慢的进入一个程序员的世界从今天开始,我们就开始一起学习css的内容一起来看看今天的重点吧,一,css的初体验css的相关设置放在style里,style放在title下,是一个双标签1.css的相关属性color:设置字体的颜色font-size:设置字体的大小background:设置字体的背景width:设置字体的宽度height:设..._前端swsf

win0如何查看计算机工作组,win10家庭版如何查看工作组计算机-程序员宅基地

文章浏览阅读5.4k次。win10家庭版如何查看工作组计算机卡饭网本站整理2019-09-16关于这个问题,小编整理了如下的五种解决方法,但是也要仔细看一下注意事项哦!方法一:桌面,右键点我的电脑—>属性—>计算机名,点“更改”按钮,就可以更改电脑的工作组名。然后去连接了打印机的电脑,打开资源管理器,把打印机共享。最后,到另一台电脑上添加网络打印机,一般按提示做就能共享了。具体的操作如下:1、设置工作组名,进..._windows10查看计算机工作组

录音自动上传到服务器,怎么实现手机录音之后,将录音的音频文件上传到服务器上...-程序员宅基地

文章浏览阅读1k次。你先得确定服务器用什么协议啊,HTTP,webservice,socket等等,如果用http一般两种方式,一个是java自带的urlhttpconnection,还有就是阿帕奇的httpclient。代码片段// 使用POST方法提交数据,必须大写conn.setRequestMethod(POST);// 需要输出流conn.setDoOutput(true);// 需要输入流conn.set..._app 录音权限 推送服务器存储

小程序点击事件插入激励视频广告实例(小白应该也能懂)_网站接入激励视频广告-程序员宅基地

文章浏览阅读8.8k次,点赞4次,收藏40次。鼓捣了一段时间,终于算是明白了,现在想想确实很简单,毕竟只是函数与函数调用的问题。首先设置需要定义广告函数,在网上看到的很多都在把他直接加在了onload函数里面,但是对于小白来言,处理不好与其他之间事件的关系,导致出错。所以我直接定义了一个广告加载函数。在js页面里//加载激励广告 adGet: function () { if (qq.createRewardedVideo..._网站接入激励视频广告

QT知识点——QT中qmake的详解-程序员宅基地

文章浏览阅读2.4k次。文章原文:https://blog.csdn.net/mybelief321/article/details/9208775#返回知识列表:1.首先,感性的认识是,qmake可以利用源文件(包括头文件h,实现文件cpp,qt的ui文件等等)生成各种不同类型的工程,工程需要的Makefile文件,可执行的与不可执行的,这取决于所用的模板(包括app、lib、subdirs、vcapp、vclib)。2.创建pro文件,添加各种源文件,还可以设定平台相关的不同源文件,设置各种规则,利用qmake命令_qt中qmake的详解

随便推点

UVM:寄存器模型 集成_寄存器层次化验证-程序员宅基地

文章浏览阅读911次。目录1. 总线适配器 adapter1.1. uvm_reg_adapteruvm_reg_adapter::reg2bus() 与 uvm_reg_adapter::bus2reg()uvm_reg_bus_op2. 寄存器模型 集成uvm_reg_map::set_sequencer(sqr,adapter)2.1. 集成于reg_sequence(个人思路)uvm_reg_sequence例码2.2. 集成于test,再向底层配置构建了寄存器模型之后,那如何将寄存器模型集成到UVM的验证框架中去呢?_寄存器层次化验证

Python解决凯撒密码问题_python凯撒密码加密解密出现的问题-程序员宅基地

文章浏览阅读572次。凯撒密码(Python)恺撒密码是古罗马恺撒大帝用来对军事情报进行加解密的算法,它采用了替换方法对信息中的每一个英文字符循环替换为字母表序列中该字符后面的第三个字符,即,字母表的对应关系如下:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬原文:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z‪‬‪‬‪‬‪‬_python凯撒密码加密解密出现的问题

斯坦福大学开放课程——编程方法 作业1-2_program karel to drop a beeper in the centre squar-程序员宅基地

文章浏览阅读1.5k次。Problem 2 Karel has been hired to repair the damage done to the Quad in the 1989 earthquake. In particular, Karel is to repair a set of arches where some of the stones (represented by beepers, of course) are missing from the columns supporting the arches,_program karel to drop a beeper in the centre square of the grid, and the

偏微分方程的正问题和逆问题(inverse problem)_偏微分方程反问题-程序员宅基地

文章浏览阅读6.9k次,点赞9次,收藏47次。正问题和逆问题_偏微分方程反问题

CentOS 7 网络配置无法ping通网关、内网及外网_centos7 配置网卡无法到网关-程序员宅基地

文章浏览阅读2.7k次。CentOS 7 网络配置无法ping通网关、内网及外网今天为了安装docker,特意安装了vm虚拟机(本人系统为win10 家庭版,并且docker对windows并不如linux友好)。但是在网络配置的时候遇到不少问题。先前自己的配置跟其他博客写的都一样。该配置的都已经配置了,但是就是ping不通外网,最后才发现连网关都ping不通,十分的懊恼。最后决定从头到尾重新配置一遍。结果问题就出来了..._centos7 配置网卡无法到网关

页面每刷新一次就更换一张背景图片_jsp怎么实现刷新一个背景更换一次-程序员宅基地

文章浏览阅读3.9k次,点赞2次,收藏8次。<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>页面每刷新一次,加载不同的背景图片</title> <style> #changebg{width: 964px;height: 460px;margin: 0 auto;} </style></head><body><div id="ch_jsp怎么实现刷新一个背景更换一次

推荐文章

热门文章

相关标签