您的位置:首页 > 其它

LayoutInflater两个inflate方法的区别

2016-04-06 18:09 197 查看
LayoutInflater类中有多个inflate方法,这里简要说一下:

public View inflate(int resource, ViewGroup root)

public View inflate(int resource, ViewGroup root, boolean attachToRoot)


这两个方法的区别,以及第二个方法中boolean变量的作用。

以前在使用ListView,Adapter的getView方法中,经常使用第一个方法来加载布局文件:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.list_item, null);
}
}


这时IDE会弹出warning:

Avoid passing null as the view root (needed to resolve layout parameters on the inflated layout’s root element)

提示我们不要传递”null”作为root的参数,因为需要决定root节点的属性。

在这里,可以换用另一个inflate方法来避免这个warning:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if (convertView == null) {
// 使用三个参数的inflate方法,设定root参数为getView中的parent参数,设定attachToRoot为false
convertView = layoutInflater.inflate(R.layout.list_item, parent, false);
}
}


使用三个参数的inflate方法,设定root参数为getView中的parent参数,设定attachToRoot为false。

这几个参数有何意义呢?我们来看一下两个inflate方法的实现。

首先两个参数的inflate方法是这样定义的:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}


root参数根据标注,是可以为null的。在函数内部,实际是调用了三个参数的inflate方法。

如果我们设定root不为空,实际等于:

layoutInflater.inflate(R.layout.list_item, parent, true);


若我们给定root为null,则实际是在调用:

layoutInflater.inflate(R.layout.list_item, null, false);


那接下来就来看一下三个参数的inflate方法的内部实现:

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();
}
}


在这里通过给定的layout资源(R.layout.*)生成了XmlResourceParser变量,并调用另一个inflate方法,因此关键步骤就在接收XmlResourceParser参数的inflate方法中了,我们来看他的内部实现,代码很多,仅保留关键步骤:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {

// 设定return的View(result)为参数root,后面以paramRoot代替
View result = root;

try {
// 查找xml文件中的root节点,后面以xmlRoot代替
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}

// 若没有开始节点,抛出异常(搜寻xmlRoot失败)
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}

final String name = parser.getName();

if (TAG_MERGE.equals(name)) {
// 若xml头节点为merge,判断是否需要attch到paramRoot
// paramRoot为null,或不需要attach到paramRoot(我们传入了null参数),抛出异常,merge标签必须要有有效的root节点
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}

// paramRoot有效,在其下载入xml子节点,然后直接到函数结束return处
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// xml头节点非merge,通过函数获取到xmlRoot节点
final View temp = createViewFromTag(root, name, inflaterContext, attrs);

ViewGroup.LayoutParams params = null;

// paramRoot不为null,来获取其param属性
if (root != null) {

params = root.generateLayoutParams(attrs);
// 如果不attach到paramRoot,则将paramRoot的param设定到xmlRoot中
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}

// 在temp下载入xmlRoot的子节点
rInflateChildren(parser, temp, attrs, true);

// 如果paramRoot不为null,并且我们设定需要attach,则使用addView,将temp添加到root中
if (root != null && attachToRoot) {
root.addView(temp, params);
}

// 如果root为null,或者我们设定不需要attach,则直接返回xmlRoot即可;
// 否则需要返回paramRoot,我们在函数一开始已经默认设置了
if (root == null || !attachToRoot) {
result = temp;
}
}

} catch (XmlPullParserException e) {

} catch (Exception e) {

} finally {

}

// 返回加载完的View
return result;
}
}


简要来说:

1. 两个参数的inflate方法实际是在内部再调用三个参数的inflate方法

2. root为null,则最终要返回xml中最外层view

3. root不为null,若不需要attach,则还是返回xml中最外层view

4. root不为null,且需要attach,则通过root的addview方法,将xml整体添加到root中。如果xml最外层是merge标签,则直接在root下加载xml中的子节点。最终返回root整体这一view。

*若给定的root为null,那么就无法将root的LayoutParams设定给xml中的父view了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: