源码分析 | Activity-setContentView 之我都不带闪的

我知道你们都很讨厌读别人写的源码分析,由于动不动就长篇大论,不讲武德,这样合适吗,这样不合适。因而,这是一篇不同的源码分析,若是看完你还说不懂。年轻人,我劝你:java

耗子尾汁是什么梗耗子尾汁意思解析及出处介绍-微侠手游网

引言

普通的一个 Activity-setContentView(),你知道它内部作了什么吗?web

概要

image-20201120151757258

源码分析

咱们先来看一下Activity-setContentView方法:windows

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
复制代码

简简单单滴方法,内部调用了 getWindows.setContentView(xxx)api

等等,Windows 是什么?markdown

Windows 表示一个窗口的概念,Android 中无论是Activity,dialog,仍是 Toast 它们的视图都是附加在 Windows 上,所以能够称 windows 是View的直接管理者。而Windows也只有实现类,即PhoneWindows.ide


咱们接着去看 PhoneWindowssetContentView()svg

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor(); //关注点
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
     mLayoutInflater.inflate(layoutResID, mContentParent);
}
复制代码

简简单单,内部执行了一个判断,而后调用 **installDecor() ** 方法。源码分析

等等,mContenParent是什么?布局

mContentParent 即放置咱们本身布局的容器,你能够理解为,它是咱们的根容器,详情看图。this


咱们接着去看 **installDecor()**方法:

private void installDecor() {
  	...忽略掉
    mDecor = generateDecor(-1); //关注点1
  	...忽略掉
  	if (mContentParent == null) {
      //关注点2
      mContentParent = generateLayout(mDecor);
    }
  	...忽略掉一大段
}
复制代码

这个方法内部很繁琐,很臭很长,咱们须要关注这么多吗,不须要,因此直接先进入 generateDecor().

等等,mDecor 是什么?

mDecorwindows 惟一视图,也就是咱们 mContentParent 的爸爸。简称 DecorView,是否是回忆起了点什么。


咱们接着去看 generateDecor() 方法

protected DecorView generateDecor(int featureId) {
  	...忽略一大段
    return new DecorView(context, featureId, this, getAttributes());
}
复制代码

哇,这个方法爱了爱了,直接new了一个 DecorView,其余也没啥,返回回去看 installDecor() 中的关注点2-generateLayout().


咱们进入 generateLayout() 方法:

protected ViewGroup generateLayout(DecorView decor) {
   //1
   TypedArray a = getWindowStyle();
   if(xx)else if(xxx)	
   else {
       layoutResource = R.layout.screen_simple;
   }
   //2
   mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
	 ..忽略掉一部分
   //3
   ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
   return contentParent;
}
复制代码
  1. 显示获取当前主题,而后开始判断究竟要用那个布局
  2. 将其加载到 DecorView
  3. 经过 findViewById(内部就是DecorView.findViewById)获取 R.id.content,并返回此viewGroup。

等等,这个 R.layout.screen_simple 是甚?

image-20201121131940286

哦,这就是咱们DecorView中加载的布局啊,具体大图以下。

image-20201121173610246

如上图所示,咱们的布局最终会被添加到这个根布局content中。

串一遍思路

咱们接下来将上面的分析总体走一遍:

  • 当咱们调用Activity的 setContentView 时,内部实际上是执行了 PhoneWindows(windows的惟一实例)的 setContenView()
  • PhoneWindowssetContentView() 内部会先判断当前有没有布局容器 contentParent,也即就是有没有 DecorView,若是没有,执行 installDecor() 去初始化咱们的 DecorViewcontentParent
  • installDecor() 方法里面,会先判断有没有 DecorView,若是没有,先new一个出来,而后判断有没有 contentParent(承载咱们本身布局的ViewGroup),没有的话,就去根据当前主题,选择一个布局,并将其当作咱们的根布局添加到 DecorView 中,再将其中的子view,即R.id.content这个view赋值给咱们的 contentParent
  • 最后 PhoneWindows-setContentView() 方法接下来就能够将咱们本身的布局 inflate 进这个根布局的 contentParent 里了;
相关文章
相关标签/搜索