天天看点

从源码的角度说说Activity的setContentView的原理

我们在Activity开发的时候天天会用到这个方法,有时候还需要根据需求在setContentView调用的时候做一些动作,因此我们就需要知道它内部是如何工作的,我们来一起看一下:

setContentView有三个重载方法:

他们实际都在调用getWindow方法返回的Window对象的setContentView方法,那getWindow对象返回的是谁呢?

我们可以看到getWindow返回的是一个mWindows的对象,那么它在哪被赋值的呢?通过查找我们可以找到在Activity的attach方法中有这么一段:

也就是说继续往下看,发现PolicyManager.makeNewWindow内部确实这样的:

好,那我们找找sPolicy又是谁:

我们可以在PolicyManager方法内看到静态代码块以及它的一些属性:

也就是说,sPolicy对象是类com.android.internal.policy.impl.Policy的一个实例,OK,我们进入这个类看一下它的makeNewWindow方法,噢噢,是这样啊:

原来那个getWindow返回的是PhoneWindow对象,setContentView调用的则是PhoneWindow的setContentView,OK,说了这么多重点就是看下PhoneWindow的setContentView方法是如何工作的:

PhoneWindow的setContentView的重载方法内部有些不同,我们先看参数为int的setContentView:

我们只看重点部分,都是通过LayoutInflater的inflate的方法加载的,是不是很熟悉呢?inflate方法的第二个参数是mContentParent,就是说要把这个layoutResID的这个布局添加到mContentParent中,那么mContentParent就是我们的主布局了,从代码中也可以看出来:

好,入口的东西都分析的差不多了,着重看一下LayoutInflater的inflate的工作原理,我们常用的方法是这3个:

其实它们都没做什么,主要做工作的是它:

这段代码比较多,我们挑一下重点看:

这段代码就是说通过createViewFromTag方法生成临时View对象,然后如果View生成成功,给它产生一个默认的LayoutParams对象附在上面,最后判断root是否为空,决定是否要将这个临时View添加到root之上,好,接下来,我们的重点是createViewFromTag方法:

这么多代码,其实我们的重点是这部分:

我们可以看到,刚开始会交给mFactory2、mFactory、mPrivateFactory这三个View工厂来进行处理,这三个对象都是通过构造方法设置进来的,如下:

这个构造方法在哪里被调用我们先不去看,我们可以继续我们的重点:

这里的意思是,如果这个Tag是没有( . )的话,那就是说这个tag是android提供的默认的控件,像View,TextView,Button等等。否则,就是其它情况了,我们先看默认没有( . )的情况:

请注意这个方法的第二个参数android.view.,然后我们进入方法内部:

这段代码其实重点就是通过ClassLoader的loadClass方法将类加载进来,然后通过反射的方式获取它的构造方法进行实例化,然后基本功能就完成了。有的同学可能会注意到这里有个mFilter属性,这个属性是用来定义这个类是否允许被加载的。

好,以上就是最基本的Inflate加载过程,其实实际过程不是这样的,我们将在下一章查看详细的加载过程。