前言 显示Activity的布局,我们实现起来很简单,只需要在onCreate()方法中setContentView(R.layout.activity_main)。今天就从源码层去看看到底系统为我们做了什么。
两大目的:
1 了解XML的解析过程
2 布局工厂Factory的生成过程以及作用
首先进入AppCompatActivity内部
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
继续向下看,可以看到AppCompatDelegate内部该方法是抽象方法,具体实现得看其实现类
(图1)
其实现类只有一个AppCompatDelegateImpl
(图2)
这里面做了什么操作呢?
1 对应的是顶级布局DecorView的初始化过程,这里不做多的介绍
2 在inflate()方法中将布局的资源id传了进去,还有就是contenparent对象,contentParent其实就是用来转载我们自己写的布局的上一层父布局。
继续向下看inflate方法,inflate里面会去调用自己的另一个重载方法
(图3)
1 :作用是生成一个xml解析器
2 :将解析器与布局资源进行向下调用
进行LayourInflater中
inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)方法中,里面的实现有点多,这里截取一段重要的地方看。
(图4)
1 进行第一段代码的内部实现看,记住我们这边传的第一个参数依然是根部局。
createViewFromTag()截图关键代码
(图5)
这里面有两段判断,我先说结论。当我们的activity继承的是AppCompatActivity的时候我们的逻辑走的是第一段代码,继承的是Acitivity走的则是第二段代码。
1 生成View对象的方式走的是mFactory.onCreateView(name, context, attrs)方法,
Factory2内部的onCreateView方法是接口内部的方法,所以得看其实现类逻辑。这个它得实现类是AppCompatDelegateImpl。继续在实现类内部方法跟踪。
(图6)
直接看到return 内部的实现
(图7)
这里可以看的,根据我们的节点不同生成不同的view对象,但是点进去看发现生成的对象并不是节点对应的控件,而是它们的子类。方式很直接是通过new().
(图8)
2 mFactory2为空的情况下,view自然也为null 进入第二段逻辑。二段代码中有一个判断是
这里判断是因为像我们的TextView 在xml布局中是没有 . 的所以会执行onCreateView方法
(图10)
(图11)
可以看的其实下层调用的还是createView(),但是方法中的第二个参数不同。进入实现方法。
(图12)
1 首先从集合中去取对应name的对象,如果没有取到执行逻辑2.
2 可以看的这个的实现是通过反射的方式,用过反射的同学肯定知道要获取到对应类一定需要通过全类名的形式。所以这里就解释了上面为什么需要去判断是否带. 没有带的情况下会传入android.view.
看的这个我们大致已经将整个view的初始化过程走了一遍,但是我带大家看的是root的初始话,后面还有布局中所以子控件的初始化。看图4的第二部分,跟踪rInflateChildren()
(图13)
这里的while循环就是遍历所以的子控件,最后再将控件add进入父布局中。
最后还有一点,我们在图5的时候直接说出了结论,继承的是AppCompatActivity的时候我们的逻辑走的是第一段代码,继承的是Acitivity走的则是第二段代码。
至于为什么?
(图14)
进入onCreate()
(图15)
这里还是一个抽象方法,看AppCompatDelegateImpl中该方法实现
(图16)
这里就对Factory2进行了赋值。而继承Activity的则没有这一个过程。
现在是不是整个布局的加载过程都清楚了。至于这个过程对我们的换肤框架有什么作用呢,我们后面再来分析。
最后附上一张完整流程图: