在android开发中,LayoutInflater
主要用于加载布局.通常在activity中,我们会使用setContentView(@LayoutRes int layoutResID);来加载activity
的布局,在Fragment的onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
中也提供了一个LayoutInflater参数用于我们加载布局.
//1.通过系统服务获取布局加载器
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(resource,root,attachToRoot);
//2.通过activity中的getLayoutInflater()方法
View view = getLayoutInflater().inflate(resource,root,attachToRoot);
//3.通过View的静态inflate()方法
View view = View.inflate(resource,root,attachToRoot);
//4.通过LayoutInflater的inflate()方法
View view = LayoutInflater.from(context).inflate(resource,root,attachToRoot);
①首先看一下Activity
中的源码
@NonNull
public LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}
发现Activity调用的是Window的getLayoutInflater.翻看源码,发现是通过Window来实现的.其实我们都知道window窗体是一个抽象类.通过Hierarchy Viewer观察,我们可以看到跟布局是一个PhoneWindow$DecorWiew
,其实PhoneWindow就是Window的实现类,PhoneWindow是在framework中的internal包下面的
public PhoneWindow(Context context)
{
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
PhoneWindow的构造方法中静态调用的方式.获取LayoutInflater实例
② 在来看一下View的源码
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
也是静态调用获取实例,都是走的第四种方式.
通过查看LayoutInflater类,发现其是一个抽象类
public abstract class LayoutInflater extends Object
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
发现最终调用的都是context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
来实现的.
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
这段代码 的意思很明了,就是说在mContentParent为空的时候installDecor,否则,移除所有的子View ,并将layout inflate出来添加到mContentParent之中.CallBack其实就是我们的Activity,
通过查看API文档,我们知道LayoutInflater.inflate有几种重载方法
public View inflate (int resource, ViewGroup root)
public View inflate (XmlPullParser parser, ViewGroup root)
public View inflate (XmlPullParser parser, ViewGroup root, boolean attachToRoot)
public View inflate (int resource, ViewGroup root, boolean attachToRoot)
一般情况下.我们不会使用第二和第三种,通过查询源码,发现最终调用的都是第三种方式.
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
最后,我们来看一下LayoutInflater中的inflate方法是怎么定义的
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
//...
View result = root;
try {
// ...
if (TAG_MERGE.equals(name)) {
// ...
} else {
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
//root != null,得到相应的ViewGroup.LayoutParams
if (root != null) {
// ...
params = root.generateLayoutParams(attrs);
// attachToRoot == false,将root 的LayoutParams设置给temp
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
//attachToRoot == true && root != null,将temp加入到root这个viewGroup中
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// root == null || attachToRoot == false,直接返回temp
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
// ....
}
return result;
}
}
就是在root != null的时候
1. ,如果 attachToRoot == false的时候,将root的LayoutParams设置给我们inflate出来的View,并返回,
2. 如果 attachToRoot == true的时候,将root的LayoutParams设置给View,并添加到root中,并返回root
3. root == null的时候,无论attachToRoot == true或者attachToRoot == false,都是直接返回改inflate出来的View
详见[LayoutInflater.inflate详解]