【Android开发经验】LayoutInflater—— 你可能对它并不了解甚至错误使用
今天,看到了一篇文章讲LayoutInflater的使用方法。瞬间感觉自己对这个类确实不够了解,于是简单的看了下LayoutInflater类的源码。对这个类有了新的认识。
首先。LayoutInflater这个类是用来干嘛的呢?
我们最经常使用的便是LayoutInflater的inflate方法。这种方法重载了四种调用方式。分别为:
1. public View inflate(int resource, ViewGroup root)
2. public View inflate(int resource, ViewGroup root, boolean attachToRoot)
3.public View inflate(XmlPullParser parser, ViewGroup root)
4.public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
这四种使用方式中。我们最经常使用的是第一种方式。inflate方法的主要作用就是将xml转换成一个View对象。用于动态的创建布局。尽管重载了四个方法。可是这四种方法终于调用的,还是第四种方式。
第四种方式也非常好理解,内部实现原理就是利用Pull解析器。对Xml文件进行解析,然后返回View对象。
我们以我们经常使用的第一种形式为例,你在重写BaseAdapter的getView方法的时候是否这样做过
public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflate(R.layout.item_row, null); } return convertView; }inflate方法有三个參数。各自是
1.resource布局的资源id
2.root填充的根视图
3.attachToRoot是否将载入的视图绑定到根视图中
在这个样例中,我们将root參数设为空,功能确实实现了。可是这里还隐藏着一个隐患。这样的方式并非inflate正确的使用姿势,以下我们通过一个Demo,来说一下这样使用造成的弊端。
首先,我们建立一个这样的项目
这里三个界面,一个主界面,两个測试界面,布局文件里。主界面仅仅负责界面跳转,两个測试界面都是一个简单的Listview,item布局显示效果例如以下
相应的布局文件例如以下
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/holo_orange_light" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="11" android:textColor="@android:color/black" android:textSize="22sp" /> </LinearLayout>
OneActivity的代码例如以下
public class OneActivity extends Activity { private ListView list1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_one); list1 = (ListView) findViewById(R.id.list1); list1.setAdapter(new MyAdapter(this)); } private class MyAdapter extends BaseAdapter { private LayoutInflater inflater; MyAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(R.layout.item_list, null); } TextView tv = (TextView) convertView.findViewById(R.id.tv); tv.setText(position+""); return convertView; } } }
TwoActivity的代码例如以下
public class TwoActivity extends Activity { private ListView list2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_two); list2 = (ListView) findViewById(R.id.list2); list2.setAdapter(new MyAdapter(this)); } private class MyAdapter extends BaseAdapter { private LayoutInflater inflater; MyAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(R.layout.item_list, parent,false); } TextView tv = (TextView) convertView.findViewById(R.id.tv); tv.setText(position + ""); return convertView; } } }
两个文件最关键的差别就一句话。
在getView方法中,OneActivity是
convertView = inflater.inflate(R.layout.item_list, null);
在getView方法中,TwoActivity是
convertView = inflater.inflate(R.layout.item_list, parent,false);
我们先看一下显示效果。再说两者的差别
OneActivity效果
TwoActivity的显示效果
我们能够非常明显的看出来,使用第一种方式,根布局的高度设置60dp没有起作用,系统还是依照包裹内容的方式载入的,为什么会产生这样的效果呢?我们从须要inflate方法的源码中找一下答案。
首先,方式一的源码实现
public View inflate(XmlPullParser parser, ViewGroup root) { return inflate(parser, root, root != null); }
当我们使用方式一,而且第二个參数传入null的时候,默认调用的是以下的方法,而且attachToRoot是false
public View inflate(int resource, ViewGroup root, boolean attachToRoot) { if (DEBUG) System.out.println("INFLATING from resource: " + resource); XmlResourceParser parser = getContext().getResources().getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }
在这一个方法中,pull解析器将资源id转化成XmlResourceParser对象,又传给了第四种方式,所以我们须要重点看的还是第四种方式是怎样实现的
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[0]; mConstructorArgs[0] = mContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } final String name = parser.getName(); if (DEBUG) { System.out.println("**************************"); System.out.println("Creating root view: " + name); System.out.println("**************************"); } if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, attrs, false); } else { // Temp is the root view that was found in the xml View temp; if (TAG_1995.equals(name)) { temp = new BlinkLayout(mContext, attrs); } else { temp = createViewFromTag(root, name, attrs); } ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } // Inflate all children under temp rInflate(parser, temp, attrs, true); if (DEBUG) { System.out.println("-----> done inflating children"); } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } } } catch (XmlPullParserException e) { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; } catch (IOException e) { InflateException ex = new InflateException( parser.getPositionDescription() + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return result; } }
代码比較长,我们重点关注以下的代码
if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } }
这些代码的意思就是,当我们传进来的root參数不是空的时候,而且attachToRoot是false的时候,也就是上面的TwoActivity的实现方式的时候,会给temp设置一个LayoutParams參数。那么这个temp又是干嘛的呢?
<pre name="code" class="java">// We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; }
如今应该明确了吧。当我们传进来的root不是null,而且第三个參数是false的时候。这个temp就被增加到了root中。而且把root当作终于的返回值返回了。而当我们设置root为空的时候,没有设置LayoutParams參数的temp对象。作为返回值返回了。
因此,我们能够得出以下的结论:
1.若我们採用convertView = inflater.inflate(R.layout.item_list, null);方式填充视图。item布局中的根视图的layout_XX属性会被忽略掉。然后设置成默认的包裹内容方式
2.假设我们想保证item的视图中的參数不被改变,我们须要使用convertView = inflater.inflate(R.layout.item_list, parent,false);这样的方式进行视图的填充
3.除了使用这样的方式,我们还能够设置item布局的根视图为包裹内容,然后设置内部控件的高度等属性。这样就不会改动显示方式了。
最后,给出那篇文章的链接http://blog.jobbole.com/72156/大家能够去看看
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5230670.html,如需转载请自行联系原作者

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
[Android Pro] Android 进程级别 和 oom_adj对应关系
一 : 前台进程 (Active Process): oom_adj为0。 前台进程包括 : 1 : 活动 正在前台接收用户输入 2:活动、服务与广播接收器正在执行一个onReceive事件的处理函数 3: 服务正在运行 onStart、onCreate或onDestroy事件处理函数。 二 : 已启动服务的进程(Started Service Process) :oom_adj值为0,这类进程包含一个已启动的服务。 服务并不直接与用户输入交互,因此服务的优先级 低于可见活动的优先级,但是,已启动服务的进程任被认为是前台进程,只有在活动以及可见活动需要资源时,已启动服务的进程才会被杀死。 三 :可见进程 (Visible Process): oom_adj 为 1。活动是可见的,但并不在前台,或者不响应用户的输入。例如,活动被非全屏或者透明的活动所遮挡。 四 :后台进程 (Backgroud Process): oom_adj 值为 2,这类进程不包含任何可见的活动与启动的服务。通常大量后台进程存在时,系统会...
- 下一篇
Android-Java 实现实时共享图像
Android-Java 实现实时共享图像,只是将代码运行起来,故此分享,代码链接源于#Testin杯#基于android的远程视频监控系统,如有问题请进入链接查看。 代码下载
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合Redis,开启缓存,提高访问速度