深入解析View的绘制源码流程

View的绘制流程

今天来讲讲View的绘制流程吧,这一块也是我比较薄弱的地方,而且之前没有什么耐心去看这一块。今天就来学习这一块的知识点。主要分为3部分:

  • View树的创建

  • ViewRootImpl的创建

  • 真正的绘制流程开始performTraversals

View树的创建

首先思考一个问题View的绘制从那里开始?关于这个问题我一开始也谷歌百度了很多东西,但是还是不能解决我的疑惑。所以今天我打算从根本上解决这个问题——从Activity的setContentView开始看。下面开始我的源码阅读过程。

Activity#setContentView
public void setContentView(@LayoutRes int layoutResID) {
   
    //注释1 getWindow()返回的是一个PhoneWindow对象,所以下一步,就是要去PhoneWindow中去看看这里面做了什么。PhoneWindow也是Window类的唯一实现类
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
PhoneWindow#setContentView
public void setContentView(int layoutResID) {
   
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    //注释2 mContentParent一开始的时候为空,所以会执行installDecor函数,mContextParent是一个ViewGroup对象
    if (mContentParent == null) {
   
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
   
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
   
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                                                       getContext());
        transitionTo(newScene);
    } else {
   
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
   
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

//installDecor的注释很长,我们一步一步看
private void installDecor() {
   
    mForceDecorInstall = false;
    //注释3 mDecor是一个DecorView,这是窗口的顶层视图,包含窗口装饰。首次进来的时候mDecor是空的,所以获取执行generateDecor,在generateDecor里面会去创建一个DecorView,注意这个函数是在PhoneWindow里面的,也就是说PhoneWindow里面的mDecor有了初始值,那么就是DecorView与PhoneWindow建立了关联。
    if (mDecor == null) {
   
        mDecor = generateDecor(-1);
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
   
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
   
        mDecor.setWindow(this);
    }
    //注释4 注意这里mContentParent还是没有进行任何的初始化,所以还是为null,所以会执行generateLayout方法,而generateLayout的方法参数是上面干初始化的mDecor,而这个函数的返回值是给mContentParent赋值。
    if (mContentParent == null) {
   
        
        //这里面得到的是一个FrameLayout
        mContentParent = generateLayout(mDecor);
        
        //....省略未分析的代码
    }
}

PhoneWindow#generateLayout
protected ViewGroup generateLayout(DecorView decor) {
   
    // Apply data from current theme.

  	//...省略很多代码,主要是获取Activity主题的一些属性,然后根据属性配置
    //注释5 这个默认情况下会为R.layout.screen_simple,screen_simple.xml的布局内容是一个LinearLayout里面包含两个子view,其中一个子view的id是content,并且是FrameLayout。
    int layoutResource;
    int features = getLocalFeatures();//获取Activity.java 代码的里面的配置,注意这里很上面的不一样,上面是根据Activity主题的配置,这里获取的是java代码里面的动态配置
    
    //...省略很多代码,
    mDecor.startChanging();
    //注释6 参数为一个LayoutInflate,和刚刚的布局文件id,这里面会调用mLayoutInflater的inflater创建view,然后调用DecorView的addView方法,也就是说刚才那个布局里面的控件都加入了DecorView中,也是就DecorView包含了他们
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

     //注释7 调用findViewById,其实调用的是DecorView的findViewById方法,然后返回一个ViewGroup。而这个id正好是注释5里面提到的content,所以这里面相当于返回了一个FrameLayout
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
	
    //省略一些配置代码
    
	//注释8 这里面将FrameLayout返回
    return contentParent;
}

在这里插入图片描述

好分析到这里,很多人已经蒙了,什么跟什么啊,一点绘制的流程都没讲。确实这里面还是没有讲解到view真正去绘制的代码,但是这里面的知识点确实很重要。如果直接讲解view的绘制流程的代码,很多人会不知道为什么执行到了具体哪一个步骤。所以上面的流程步骤先耐心看完吧。我们现在有了什么?总结一下,我们有了DecorView,有了一个FrameLayout,还有一些可能配置的信息,比如TitleBar,他们的关系是怎么样的呢?如下图。

想一个问题,这里面是系统的层面的布局给改好了,我们传入的布局呢?这时候就需要回到PhoneWindow#setContentView里面了。

public void setContentView(int layoutResID) {
   
	//省略已经分析过的代码

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值