在使用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。

最新文章

  1. Java输入输出流进阶
  2. 百度地图api根据地图缩放等级显示不同的marker点,功能二
  3. 增量式PID简单翻板角度控制
  4. Spring addFlashAttribute
  5. css居中的几种方式
  6. [置顶] 问题解决——XP线程池找不到QueueUserWorkItem
  7. C++程序设计的技巧-Pimple的使用
  8. AndroidUI 布局动画-布局内容改变动画
  9. android电源“有毒”移动电源Android版的设计及其实现
  10. JDK内置日志系统
  11. CSS3背景渐变。。。
  12. Oracle_复杂查询综合
  13. Node 框架接入 ELK 实践总结
  14. python 中 try catch finally语句中含有return语句的执行情况
  15. Java 时间总结
  16. python基础之IO编程
  17. Python查看与安装
  18. python中dir(),__dict__
  19. Page6:关于能控性、能观性、能测性及其判据(1)[Linear System Theory]
  20. 使用LVM方式安装Ubuntu 16.04

热门文章

  1. 高阶Laplace曲面形变算法(Polyharmonic Deformation)
  2. GLine游戏(Win32GUI实现,CodeBlocks+GCC编译)
  3. jenkins,jmeter,ant持续集成
  4. fMRI: spatial smoothing
  5. 数据表格 - DataGrid - 行编辑
  6. 初试Scala解析XML
  7. 谈谈计算机上的那些存储器-Memory Hierarchy
  8. 玩蛇记--Python处理海量手机号码
  9. Ceph RGW 的 OSPF负载均衡 + quagga的配置
  10. jQuery.extend和jQuery.fn.extend的区别【转】