在使用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. BZOJ 3112: [Zjoi2013]防守战线 [单纯形法]

    题目描述 战线可以看作一个长度为n 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第i 号位置上建一座塔有Ci 的花费,且一个位置可以建任意多的塔,费用累加计算.有m 个区间[L1, R1], [ ...

  2. UVA 11404 Palindromic Subsequence[DP LCS 打印]

    UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求L ...

  3. UVA - 11134 Fabled Rooks[贪心 问题分解]

    UVA - 11134 Fabled Rooks We would like to place n rooks, 1 ≤ n ≤ 5000, on a n × n board subject to t ...

  4. java1.8函数式接口

    package com.wzy.t1; @FunctionalInterface//此注解用来声明此接口为函数式接口 public interface People { /** * 1.函数式接口只能 ...

  5. idea如何设置类头注释和方法注释

    CSDN 2016博客之星评选结果公布      [系列直播]算法与游戏实战技术      "我的2016"主题征文活动 详细:idea如何设置类头注释和方法注释 标签: idea ...

  6. JS重载

    Js 不支持函数的重载,可以用相同的名字在同一作用区域,定义两个函数,而不会引起错误,但真正使用的是最后一个. Js 不会验证传递给函数的参数个数是否和函数定义的参数的个数相同,开发人员定义的函数都可 ...

  7. tagfield

  8. C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 面向全国标准省市县行政数据基础之上的组织机构管理

    由于信息系统庞大.各种业务子系统.各种开发语言开发的业务逻辑.各种年代维护的代码.各种参差不齐的历史遗留信息系统,面向全国的业务系统,面向某个领域的汽运管理信息系统,面向内部的业务系统,面向外部的各种 ...

  9. TCP/IP协议

    1.为什么有了IP地址还需要MAC地址? 首先,数据或者信息在网络上的传输需要两个地址:目的地址和下一跳地址.其中IP地址就是目的地址,而MAC地址则是下一跳地址.目的地址在经过路由器转发的时候是不会 ...

  10. js兼容获取元素的样式

    js获取元素的样式的兼容性处理: function getStyle(obj,attr){ return obj.currentStyle?obj.currentStyle[attr]:getComp ...