在使用ListView的时候,我们传给setAdapter方法的Adapter通常是ArrayAdapter、SimpleAdapter、BaseAdapter,但是这几个Adapter内部究竟是什么样子如果我们不搞清楚的话,在使用的时候就会感觉有些混乱,概括的说这三个Adapter之间的差异主要是由他们各自的getView方法的差异造成的,接下来我们一起看一下这几个Adapter的getView的源码

1.ArrayAdapter的getView方法源码如下:

    public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
} private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
ViewGroup parent, int resource) {
View view;
TextView text; if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
} try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = (TextView) view.findViewById(mFieldId);
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
} T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence)item);
} else {
text.setText(item.toString());
} return view;
}

  可以看到ArrayAdapter的getView方法直接调用了createViewFromResource方法,在这个方法里面用到了一个成员变量mFieldId ,我们往上翻一下源码可以看到他的定义如下:

private int mFieldId = 0;

  再接着翻源码可以看到mFieldId的值只在构造函数中修改:

    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
@NonNull List<T> objects) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
mObjects = objects;
mFieldId = textViewResourceId;
}

  此时我们可以明白mFieldId的值就是在构造ArrayAdapter时传入的textViewResourceId,也就是布局文件中TextView的android:id属性的值,弄明白mFieldId后,我们接着分析,可以看到接下来对mFieldId进行了判断,如果mFieldId的值是0,那么传入整个布局文件的根节点就是一个TextView,如果mFieldId的值不为0,就在传入的布局文件中查找android:id为mFieldId的TextView,之后用getItem方法获取TextView的文字内容,然后用text的setText方法设置标题,至此我们可以明白ArrayAdapter只能对TextView及TextView的子类进行定制,ListView的每一项可以仅仅是一个TextView,也可以是一个布局文件,但是这个布局文件里面必须且只能包含一个android:id属性为textViewResourceId的TextView(TextView的子类当然也可以,因为他的子类也属于TextView)。

2.接下来分析SimpleAdapter,他的getView方法源码如下:

    public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
} private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
ViewGroup parent, int resource) {
View v;
if (convertView == null) {
v = inflater.inflate(resource, parent, false);
} else {
v = convertView;
} bindView(position, v); return v;
}

  可以看到,在他的getView方法里面依然是调用了createViewFromResource方法,只是createViewFromResource方法和ArrayAdapter的createViewFromResource不同,在SimpleAdapter的createViewFromResource方法里面又调用了bindView方法,我们看一下bindView的源码:

    private void bindView(int position, View view) {
final Map dataSet = mData.get(position);
if (dataSet == null) {
return;
} final ViewBinder binder = mViewBinder;
final String[] from = mFrom;
final int[] to = mTo;
final int count = to.length; for (int i = 0; i < count; i++) {
final View v = view.findViewById(to[i]);
if (v != null) {
final Object data = dataSet.get(from[i]);
String text = data == null ? "" : data.toString();
if (text == null) {
text = "";
} boolean bound = false;
if (binder != null) {
bound = binder.setViewValue(v, data, text);
} if (!bound) {
if (v instanceof Checkable) {
if (data instanceof Boolean) {
((Checkable) v).setChecked((Boolean) data);
} else if (v instanceof TextView) {
// Note: keep the instanceof TextView check at the bottom of these
// ifs since a lot of views are TextViews (e.g. CheckBoxes).
setViewText((TextView) v, text);
} else {
throw new IllegalStateException(v.getClass().getName() +
" should be bound to a Boolean, not a " +
(data == null ? "<unknown type>" : data.getClass()));
}
} else if (v instanceof TextView) {
// Note: keep the instanceof TextView check at the bottom of these
// ifs since a lot of views are TextViews (e.g. CheckBoxes).
setViewText((TextView) v, text);
} else if (v instanceof ImageView) {
if (data instanceof Integer) {
setViewImage((ImageView) v, (Integer) data);
} else {
setViewImage((ImageView) v, text);
}
} else {
throw new IllegalStateException(v.getClass().getName() + " is not a " +
" view that can be bounds by this SimpleAdapter");
}
}
}
}
}

这时我们发现终于找到关键代码了,bindView先是获取第一项的数据dataSet ,然后通过to.length获取ListView的每一个列表项里面有几个要填充的控件,接下来是一个for循环,判断列表项里面的每个要填充的控件是具体什么东东,是Checkable还是TextView,还是ImageView。至此我们明白了SimpleAdapter只能填充Checkable、TextView、ImageView三种控件,在ListView的每一个列表项里面可以包含1~N个上面的三种控件,可以只有一种,也可以有两种,也可以都有,我们也可以看出每一个列表项都只能是一样的,通过SimpleAdapter我们不能让某个列表项和其他列表项不一样,通过继承BaseAdapter来自己实现getView则可以让我们任意定制列表项,在getView里面我们可以根据position的值决定返回何种类型的view。

深入理解使用ListView时ArrayAdapter、SimpleAdapter、BaseAdapter的原理的更多相关文章

  1. 使用ListView时遇到的问题

    这周练习ListView时遇到了一个问题,从数据库中查询出的数据绑定到LIstView上,长按某个item进行删除操作,每次点击item取得的id都不对,调了半天终于找到了原因,关键是自己对自定义的B ...

  2. 第28讲 UI组件之 ListView和ArrayAdapter

    第28讲 UI组件之 ListView和ArrayAdapter 1. Adapter 适配器 Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带.在常见的 ...

  3. 42.Android之ListView中ArrayAdapter简单学习

    今天学习下Android中ListView关于ArrayAdapter数据绑定, 废话少说直接上代码. 改下布局文件: <?xml version="1.0" encodin ...

  4. 滚动ListView时图像顺序混乱

    本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术.本文将为读者讲解滚动ListView时图像顺序混 ...

  5. Android新手入门2016(8)--ListView之ArrayAdapter

    本文来自肥宝传说之路,引用必须注明出处! ListView是Android中经常使用的控件. 什么是列表视图,让我们先看看图: watermark/2/text/aHR0cDovL2Jsb2cuY3N ...

  6. 深入理解自定义ListView

    深入理解自定义ListView ListView原理 他是一个系统的原生控件,用列表的形式来显示内容.如果内容过过有1000条左右,我们可以通过手势的上下滑动来查看数据.ListView也不是爆出OO ...

  7. SimpleAdapter & BaseAdapter

    [SimpleAdapter & BaseAdapter] 参考:http://blog.csdn.net/shakespeare001/article/details/7926783

  8. 第28 章 : 理解容器运行时接口 CRI

    理解容器运行时接口 CRI CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分.本文将主要分享以下三方面的内容: CRI 介绍 CRI 实现 相关工具 CRI 介绍 在 CRI ...

  9. IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理

    1.前言 一个安全的信息系统,合法身份检查是必须环节.尤其IM这种以“人”为中心的社交体系,身份认证更是必不可少. 一些PC时代小型IM系统中,身份认证可能直接做到长连接中(也就是整个IM系统都是以长 ...

随机推荐

  1. Spring MVC 访问静态资源

    当我们不通过控制器,想直接访问网站上的静态资源时,由于DispatcherServlet的url-patten的通配符的限制,导致系统会认为你访问的是个url映射,这时需要配置一个东西就可以解决问题了 ...

  2. Freemarker与普通java

    package com.sxt.test.freemarker; import java.io.File; import java.io.OutputStreamWriter; import java ...

  3. Spring多种注入方式及注解实现DI

    一.Bean作用域 spring容器创建的时候,会将所有配置的bean对象创建出来,默认bean都是单例的.代码通过getBean()方法从容器获取指定的bean实例,容器首先会调用Bean类的无参构 ...

  4. java内部类

    1.内部类 2.内部类的名字不会单独存在,根据外部类名的存在而存在.内部类的名字可以和外部其他类的名字一样. 3.这个this.num打印的是inner类里面的num 4.在内部类访问外部类成员变量方 ...

  5. sublime text nodejs set

    把新建的system清空,输入{ "cmd": ["node", "$file"], "selector": " ...

  6. codeforces 711E. ZS and The Birthday Paradox 概率

    已知一年365天找23个人有2个人在同一天生日的概率 > 50% 给出n,k ,表示现在一年有2^n天,找k个人,有2个人在同一天生日的概率,求出来的概率是a/b形式,化到最简形式,由于a,b可 ...

  7. 详解mysql int类型的长度值问题【转】

    mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允 ...

  8. WPF中RadioButton绑定数据的正确方法

    RadioButton一般用于单选的时候,也就是从一组值中选择一个值. 比如性别有“男”和“女”两种取值,而对于一个员工的实例来说,性别的取值要么是男,要么是女. 这种时候一般就会用到RadioBut ...

  9. RGW/SWIFT对象存储性能测试工具--COSBench安装

    Cosbench是Intel的开源云存储性能测试软件,COSBench目前已经广泛使用与云存储测试,并作为云存储的基准测试工具使用 https://github.com/intel-cloud/cos ...

  10. python实现计算器

    计算器功能 实现优先级解析,加减乘除四则运算 自定义小数位精度 实现思想: 先找到最里层括号,根据乘除,加减优先级,调用写好的乘除.加减运算函数算出括号内总值,再将原括号式用所得值替换,此过程循环进行 ...