public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context)mConstructorArgs[0];
mConstructorArgs[0] = mContext;
View result = root;
try {
// 查找根節(jié)點(diǎn)
...
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
rInflate(parser, root, attrs, false, false);
} else {
//創(chuàng)建根View
final View temp = createViewFromTag(root, name, attrs, false);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
//遞歸創(chuàng)建子View
rInflate(parser, temp, attrs, true, true);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
return result;
}
}
過(guò)程大致如下:
- 首先根據(jù)layout的資源id察藐,創(chuàng)建對(duì)應(yīng)的XmlResouceParser
- XMLResourceParser找到根標(biāo)簽。
- 如果根標(biāo)簽不是merge的話(huà)舟扎,則通過(guò)createViewFromTag創(chuàng)建相應(yīng)的View分飞,然后遞歸的創(chuàng)建子View
- 如果設(shè)置了attachToRoot,則將將根View添加到rootView中睹限,然后返回rootView譬猫;否則返回根view讯檐。
xml中根節(jié)點(diǎn)設(shè)置的layout_width和Layout_height有時(shí)不起作用,關(guān)鍵要看infalte時(shí)染服,是否傳了rootView别洪,并設(shè)置attachToRoot為true。
View createViewFromTag(View parent, String name, AttributeSet attrs, boolean inheritContext) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
Context viewContext;
if (parent != null && inheritContext) {
viewContext = parent.getContext();
} else {
viewContext = mContext;
}
// 應(yīng)用主題
final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0) {
viewContext = new ContextThemeWrapper(viewContext, themeResId);
}
ta.recycle();
try {
View view;
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, viewContext, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, viewContext, attrs);
} else {
view = null;
}
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, viewContext, attrs);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = viewContext;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
return view;
}
依次分別由mFactory2柳刮、mFactory挖垛、mPrivateFactory創(chuàng)建View,如果都沒(méi)有創(chuàng)建诚亚,則由LayoutInflater自己創(chuàng)建晕换。
下面看看LayoutInflater是如何創(chuàng)建的
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
Class<? extends View> clazz = null;
try {
if (constructor == null) {
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
constructor = clazz.getConstructor(mConstructorSignature);
sConstructorMap.put(name, constructor);
} else {
Object[] args = mConstructorArgs;
args[1] = attrs;
constructor.setAccessible(true);
final View view = constructor.newInstance(args);
return view;
}
LayoutInflater內(nèi)有View構(gòu)造函數(shù)的緩存午乓,當(dāng)存在該View的構(gòu)造函數(shù)時(shí)站宗,直接拿來(lái)創(chuàng)建實(shí)例,否則通過(guò)context.getClassLoader益愈,由classLoader去loadClass梢灭,然后獲得該類(lèi)的構(gòu)造函數(shù),并存入緩存蒸其,然后調(diào)用構(gòu)造函數(shù)創(chuàng)建View敏释。
那mFactory2、mFactory和mPrivateFactory是用來(lái)干什么的呢摸袁?它們之間是什么關(guān)系钥顽?這三個(gè)變量是何時(shí)被賦值的?
第一個(gè)問(wèn)題的答案是靠汁,可以對(duì)LayoutInflater從xml中創(chuàng)建View的過(guò)程進(jìn)行擴(kuò)展蜂大。
對(duì)于第二個(gè)問(wèn)題,來(lái)看一下Factory和Factory2的定義
public interface Factory {
public View onCreateView(String name, Context context, AttributeSet attrs);
}
public interface Factory2 extends Factory {
public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}
Factory2繼承于Factory蝶怔,增加了一個(gè)接口奶浦。其中mFractory是Factory類(lèi)型的,mFactory2和mPrivateFactory是Factory2類(lèi)型的踢星。你要是去看Android源碼修改日志的話(huà)澳叉,可以看到最初的時(shí)候只有mFactory,后來(lái)為了支持Fragment才增加了mFactory2沐悦,后來(lái)又有了mPrivateFactory成洗。
之所以還留著Factory,是為了向下兼容藏否。
第三個(gè)問(wèn)題瓶殃,三個(gè)Factory是何時(shí)被賦值的?
如果看一下Activity的定義的話(huà)秕岛,你會(huì)發(fā)現(xiàn)Activity實(shí)現(xiàn)了Factory2接口碌燕。并且在attach方法中误证,將自己設(shè)置為L(zhǎng)ayoutInflater的privateFactory。
mWindow.getLayoutInflater().setPrivateFactory(this);
這是你就會(huì)明白了修壕,當(dāng)我們使用LayoutInflater來(lái)inflate View的時(shí)候愈捅,首先會(huì)走到Activity的onCreateView中,如果返回了null慈鸠,才會(huì)由LayoutInflater繼續(xù)創(chuàng)建View蓝谨。我們來(lái)看一下Activity的onCreateView是如何實(shí)現(xiàn)的
public View onCreateView(String name, Context context, AttributeSet attrs) {
return null;
}
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
if (!"fragment".equals(name)) {
return onCreateView(name, context, attrs);
}
return mFragments.onCreateView(parent, name, context, attrs);
}
如果是fragment的話(huà),則由mFragments去創(chuàng)建青团,否則返回null譬巫。
而mFragments的類(lèi)型是FragmentManagerImpl。
這樣就說(shuō)的通了督笆,以前的時(shí)候Android是不支持Fragment的芦昔,View都由LayoutInflater直接創(chuàng)建,后來(lái)為了支持Fragment娃肿,讓Activity來(lái)實(shí)現(xiàn)Factory2咕缎,從而攔截對(duì)Fragment的創(chuàng)建,后來(lái)又把Fragment相關(guān)的代碼移到了FragmentManager中料扰。
這時(shí)候你可以會(huì)說(shuō)凭豪,我用的不是Activity,而是FragmentActivity晒杈。
在BaseFragmentActivityDonut代碼中
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
getLayoutInflater().setFactory(this);
}
super.onCreate(savedInstanceState);
}
如果系統(tǒng)Build版本小于11嫂伞,LayoutInflater的mFactory被設(shè)置為Activity,而11之后拯钻,則是mPrivateFactory被設(shè)置為Activity帖努。