您的位置:首页 > 其它

获取LayoutInflater对象的方法和inflate方法的一些参数问题

2017-03-01 20:55 621 查看
一、获取LayoutInflater的三种方法

1、

LayoutInflater layoutInflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);


2、

LayoutInflater layoutInflater = LayoutInflater.from(MainActivity.this);


3、

LayoutInflater layoutInflater = MainActivity.this.getLayoutInflater();


其实查看它们的源码就会发现,后两种方法最终也还是调用第一种方法的context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)。不过查看第三种方法的源码要稍微绕一下,因为activity.getLayoutInflater(),其实是调用Window类的getLayoutInflater(),而这个是抽象类。根据这个类的注释,可以查看它的子类PhoneWindow,而这个是内部类,用开发工具是找不到这个类的,要手动去找。可以从sdk的文件目录下找,例如,我的是“D:\Android\Sdk\sources\android-23\com\android\internal\policy”。也可以直接在sdk目录下,搜索该类就行了。

其实View有一个静态的inflate方法,连LayoutInflater对象都帮你内部创建了。其方法源码如下:

public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}


 

 二、inflate方法的一些参数问题

以前是困惑于inflate方法的作用。现在是困惑于什么时候才传入ViewGroup对象和attachToRoot的取值。所以分析了一下源码。

当写ListView的Adapter时,总要在getView方法里调用inflate方法,例如:

convertView = LayoutInflater.from(mContext).inflate(R.layout.push_to_refresh_header, parent, 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();
}
}


这个时候传入的ViewGroup对象不为nullt,同时设置boolean attachToRoot为false。

 

而在动态添加布局的时候,我学到的是下面这种写法:

View refreshView = layoutInflater.inflate(R.layout.push_to_refresh_header, null);
linearLayout.addView(refreshView);


这个inflate方法的源码是:

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


这个时候
4000
传入的ViewGroup对象为null。

 

可以看到,当调用两个参数的inflate方法时,它会以ViewGroup对象不等于空的判断值为参数attachToRoot的值,并和之前的参数传到另一个带有三个参数的inflate方法。

最终都会调用下面这个inflate方法。这里我们只需关注ViewGroup root、boolean attachToRoot和返回值result就可以了,所以我把其它省略了。

1     public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
2         synchronized (mConstructorArgs) {
         ......
 9             View result = root;
10
11             try {
           ......
32
33                 if (TAG_MERGE.equals(name)) {
              ......
40                 } else {
41                     // Temp is the root view that was found in the xml
42                     final View temp = createViewFromTag(root, name, inflaterContext, attrs);
43
44                     ViewGroup.LayoutParams params = null;
45
46                     if (root != null) {
                ......
51                         // Create layout params that match root, if supplied
52                         params = root.generateLayoutParams(attrs);
53                         if (!attachToRoot) {
54                             // Set the layout params for temp if we are not
55                             // attaching. (If we are, we use addView, below)
56                             temp.setLayoutParams(params);
57                         }
58                     }
              ......
70
71                     // We are supposed to attach all the views we found (int temp)
72                     // to root. Do that now.
73                     if (root != null && attachToRoot) {
74                         root.addView(temp, params);
75                     }
76
77                     // Decide whether to return the root that was passed in or the
78                     // top view found in xml.
79                     if (root == null || !attachToRoot) {
80                         result = temp;
81                     }
82                 }
83
84             }
         ......
102             return result;
103         }
104     }


在第9行可以看到返回值result的初始值是root。

然后整个方法就只有第79行的if语句会修改result。而条件就是root为null,或者attachToRoot为假。而这个temp在第42行可以找到初值。其实上面的注释已经告诉我们,temp是我们传入的布局文件中的根视图。

在Adapter的getView方法里,虽然传入的root不为null,但attachToRoot为false,所以返回值就是我们传入的布局文件中的根视图,用来为布局中的控件初始化和修改。而上面那种动态添加布局的方式,传入的root为null,也是如此。

那为什么getView方法不直接传进null呢?这个我没能从源码上找到为什么,只知道,当传进ViewGroup对象为null时,运行会报错,说Adapter为null,就是Adapter对象没有初始化。那如果传进了root,但令attachToRoot为true呢?也是会运行报错。

先看看第73行的if语句。它表示的是root不为null,同时attachToRoot为true时,就会把temp和它的布局参数添加到root中。

所以在上面那种情况中,root其实就是ListView,而在ListView的父类AdapterView中,其方法的注释声明了是不支持addView方法的,一旦调用就会报错。

而我上面动态添加布局的那种写法,也就可以替换成:

View refreshView = layoutInflater.inflate(R.layout.push_to_refresh_header, linearLayout);


把父布局的根视图传进去就可以了,它会自动生成attachToRoot的值为true。然后再把要添加的布局中的根视图添加到root中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: