ViewRootImpl到底是什么

本文详细解析了ViewRootImpl在Android中的角色,指出它是View的抽象概念,作为DecorView的ParentView,通过WindowManager添加到视图层次结构。作者还讨论了ViewParent接口和DecorView的初始化过程。
摘要由CSDN通过智能技术生成

1. 对ViewRootImpl的疑问和我的见解

相信很多朋友刚学习Android的View相关的内容的时候都纠结一个问题,ViewRootImpl到底是何方神圣。我就结合下我在学习的过程中总结的谈下我对ViewRootImpl的理解吧。当然其中也会穿插一些我的疑问,欢迎大家一起讨论。

先来说下结论吧,我认为ViewRootImpl是一个概念,他不是View,他和view属于兄弟关系,他可以作为View(DecorView)的ParentView,从定义也可以看出来:

	
public final class ViewRootImpl implements ViewParent
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
        AttachedSurfaceControl

2. ViewRootImpl的属性

ViewRootImpl实现了接口ViewParent,那ViewParent又是什么呢?可以把View树理解成一个n叉树,那么每一个view是不是都是有一个父节点和n个子节点嘛,而Viewparent就是这么一个接口,实现了ViewParent,就说明这个view可以作为一个父节点,并切接口中声明了一些父节点需要实现的方法。
而且在View.java中我们就能找到这么一个属性, protected ViewParent mParent;
下面画了一个简易的view树如图1,便于理解。所以DecorView的结构可以看成图2(DecorView的布局有很多种,这里我们就选择了其中一个作为演示)。可以看到DecorView还有两个子View,其中一个就是mContentParent,这就让我们想到自己写的onCreate方法中的setContentView了,这个详细的我们后面再说,总之当我们去写一个程序时,调用setContentView的时候,就是在编辑这个mContentParent(这里需要声明下,mContentParent这个名称是在phoneWindow类中存在的,在DecorView类中,他的名称是mContentRoot)下面的布局。

在这里插入图片描述在这里插入图片描述

然后再看一个我们最常见的view,FrameLayout,他的定义又是什么呢?

public class FrameLayout extends ViewGroup 

看这里,FrameLayout就是继承自ViewGroup,而ViewGroup又实现了ViewParent,其实我们常见的View都是继承自View并且实现了ViewParent,所以这里就可以看到ViewRootImpl和View是不一样的东西,而ViewRootImpl之所以能作为DecorView的ParentView就是因为他实现了ViewParent,所以他是可以作为View的父节点的,因为父节点的类型只要是ViewParent就行。

3. ViewRootImpl和DecorView的关系

接下来再讲怎么成为DecorView的ViewParent吧。这里就得牵扯到WindowManagerGlobal类了。 在WindowManagerGlobal类中的addView方法中,会初始化ViewRootImpl,这里能看到root就是ViewRootImpl的实例。那DecorView的实例是谁呢?

          if (windowlessSession == null) {
                root = new ViewRootImpl(view.getContext(), display);
            } else {
                root = new ViewRootImpl(view.getContext(), display,
                        windowlessSession, new WindowlessWindowLayout());
            }

            view.setLayoutParams(wparams); 

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
                // BadTokenException or InvalidDisplayException, clean up.
                if (viewIndex >= 0) {
                    removeViewLocked(viewIndex, true);
                }
                throw e;
            }

答案就是view。能调用到这里的addView方法的,都是通过windowManager调用过来的,而查看下代码,用到WindowManagerImpl实现了WindowManager接口,所以直接看哪里调用了WindowManagerImpl的addView方法就好了。

而这里我们可以看到在handleResumeActivity方法中有这么一句,看这里addView的参数decor就是DecorView的实例,最后传到了上面的 root.setView(view, wparams, panelParentView, userId);这里的view就是decor一路传过来的。

          if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                } else {
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }

再进入到setView方法看下,是怎么把root变成view的ParentView的吧。 然后再看到这里,很明显了吧,已经把view赋值给root了。

                view.assignParent(this);
                mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
                mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;

好了这次先说这么多,这里的知识点很多,比如DecorView的加载我还没说,后面会补充的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值