Adapter 是将数据绑定到 UI 界面上的桥接类。 Adapter 负责创建显示每个项目的子 View 和提供对下层数据的访问。
支持 Adapter 绑定的 UI 控件必须扩展 AdapterView 抽象类。创建自己的继承自 AdapterView 的控件和创建新的 Adapter 类来绑定它们是可能的。
一些 Android 提供的 Adapter 介绍
在多数情况下,你不需要白手创建自己的 Adapter 。 Android 提供了一系列 Adapter 来将数据绑定到 UI Widget 上。
因为 Android 负责提供数据和选择用于显示每个项目的 View ,所以 Adapter 能快速地修改要绑定的控件的外观和功能。下面的列表显示了两个最有用和最通用的本地 Adapter :
❑ ArrayAdapter
ArrayAdapter 是一个绑定 View 到一组对象的通用类。默认情况下, ArrayAdapter 绑定每个对象的 toString 值到在 layout 中预先定义的 TextView 控件上。可变通的,构造函数允许你使用更加复杂的 layout 或者通过重写 getView 方法来扩展类从而使用 TextView 的替代物(如 ImageView 或嵌套的 layout )。
❑ SimpleCursorAdapter
SimpleCursorAdapter 绑定 View 到 Content Provider 查询返回的游标上。指定一个 XML layout 定义,然后将数据集中的每一列的值绑定到 layout 中的一个 View 上。
接下来的章节将深入挖掘这些 Adapter 类的细节。例子中,提供了绑定数据到 ListView 上,尽管这个逻辑会和其他一些 AdapterView 类(如 Spinner 和 Gallery )工作的一样。
使用 Adapter 进行数据绑定
将 Adapter 应用到继承自 AdapterView 类上,你需要调用 View 的 setAdapter 方法,传入一个 Adapter 实例,如下面的片段所示:
ArrayList<String> myStringArray = new ArrayList<String>();
ArrayAdapter<String> myAdapterInstance;
int layoutID = android.R.layout.simple_list_item_1;
myAdapterInstance = new ArrayAdapter<String>(this, layoutID, myStringArray);
myListView.setAdapter(myAdapterInstance);
这个片段显示了最简单的情况,将数组中的字符串绑定到 ListView 中用于显示每个项目的简单 TextView 控件上。
接下来的第一个例子显示了如何绑定一组复杂的对象到 ListView 上,使用一个自定义的 layout 。第二个例子显示了如何使用 SimpleCursorAdapter 来绑定查询结果到 ListView 中的自定义 layout 上。
在android开发中列表的使用是十分常见的。google对列表的封装使列表既有显示传统文本列表的能力,也有加入了诸如选择项、复选项等处理事件的能力。这里写一些我这几天对这个问题的理解。
在android的api中,LIST和adapter都被放在了android.widget包内。包内的具体结构我这里先不展示了,主要侧重列表和adapter。adapter的作用就是将要在列表内显示的数据和列表本身结合起来。列表本身只完成显示的作用,其实他就是继承自VIEWGROUP类。但是他又有一个独特的函数就是setAdapter()就是完成了view和adapter的结合。adapter如同其本身含义,其实就是一个适配器,他可以对要显示的数据进行统一的封装,主要是将数据变成view提供给list。
我们先来看看adapter的体系:
public interface Adapter----0层(表示继承体系中的层次)
public interface ExpandableListAdapter---(无所谓层次因为没有其他接口继承实现它)
这是adapter的始祖,其他个性化的adapter均实现它并加入自己的接口。
public interface ListAdapter----1层
public interface SpinnerAdapter----1层
public interface WrapperListAdapter----2层(实现ListAdapter)
以上接口层面上的体系已经完了。可以看出来作为widget view的桥梁adapter其实只分为2种:ListAdapter和SpinnerAdapter以及ExpandableListAdapter。也就是说所有widget也就是基于list和spinne与ExpandableList三种view形式的。
由于在实际使用时,我们需要将数据加入到Adapter,而以接口形式呈现的adapter无法保存数据,于是Adapter就转型为类的模式。
public abstract class BaseAdapter----2层(实现了ListAdapter和SpinnerAdapter)
以抽象类的形式出现构造了类型态下的顶层抽象,包容了List和Spinner
public class ArrayAdapter----3层
public class SimpleAdapter---3层
public class CursorAdapter----3层(CursorAdapter其后还有子类这里先不探讨)
基本体系有了之后,让我们看看顶层Adapter里有哪些方法(只列举常用的):
abstract Object getItem(int position)
abstract int getCount()
abstract long getItemId(int position)
abstract int getItemViewType(int position)
abstract View getView(int position,View convertVeiw,ViewGroup parent)
以上是比较重要的方法,ArrayAdapter他们也是重新实现以上方法的。在实际的开发过程中,往往我们要自己做属于自己的Adapter,以上方法都是需要重新实现的。
ArrayAdapter和SimpleCursorAdapter例子
使用ArrayAdapter定制 To-Do List
这个例子将扩展 To-Do List 工程,以一个 ToDoItem 对象来储存每一个项目,包含每个项目的创建日期。
你将扩展 ArrayAdapter 类来绑定一组 ToDoItem 对象到 ListView 上,并定制用于显示每一个 ListView 项目的 layout 。
1. 返回到 To-Do List 工程。创建一个新的 ToDoItem 类来保存任务和任务的创建日期。重写 toString 方法来返回一个项目数据的概要。
package com.paad.todolist; import java.text.SimpleDateFormat; import java.util.Date; public class ToDoItem { String task; Date created; public String getTask() { return task; } public Date getCreated() { return created; } public ToDoItem(String _task) { this(_task, new Date(java.lang.System.currentTimeMillis())); } public ToDoItem(String _task, Date _created) { task = _task; created = _created; } @Override public String toString() { SimpleDateFormat sdf = new SimpleDateFormat(“dd/MM/yy”); String dateString = sdf.format(created); return “(“ + dateString + “) “ + task; } }
2. 打开 ToDoList Activity ,修改 ArrayList 和 ArrayAdapter 变量的类型,储存 ToDoItem 对象而不是字符串。然后,你将修改 onCreate 方法来更新相应的变量初始化。你还需要更新 onKeyListener 处理函数来支持 ToDoItem 对象。
3. 如果你运行 Activity ,它将显示每个 to-do 项目,如图 5-3 所示。
图 5-3
4. 现在,你可以创建一个自定义的 layout 来显示每一个 to-do 项目。修改在第 4 章中创建的自定义 layout ,包含另外一个 TextView ,它将用于显示每个 to-do 项目的创建日期。
<?xml version=”1.0” encoding=”utf-8”?> <RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android” android:layout_width=”fill_parent” android:layout_height=”fill_parent” android:background=”@color/notepad_paper”> <TextView android:id=”@+id/rowDate” android:layout_width=”wrap_content” android:layout_height=”fill_parent” android:padding=”10dp” android:scrollbars=”vertical” android:fadingEdge=”vertical” android:textColor=”@color/notepad_text” android:layout_alignParentRight=”true” /> <TextView android:id=”@+id/row” android:layout_width=”fill_parent” android:layout_height=”fill_parent” android:padding=”10dp” android:scrollbars=”vertical” android:fadingEdge=”vertical” android:textColor=”@color/notepad_text” android:layout_alignParentLeft=”@+id/rowDate” /> </RelativeLayout>
5. 创建一个新的类( ToDoItemAdapter ),使用指定的 ToDoItem 变量来扩展一个 ArrayAdapter 。重写 getView 方法来将 ToDoItem 对象中的 task 和 date 属性指定给第 4 步创建的 layout 中的 View 。
import java.text.SimpleDateFormat; import android.content.Context; import java.util.*; import android.view.*; import android.widget.*; public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> { int resource; public ToDoItemAdapter(Context _context,int _resource, List<ToDoItem> _items) { super(_context, _resource, _items); resource = _resource; } @Override public View getView(int position, View convertView, ViewGroup parent) { LinearLayout todoView; ToDoItem item = getItem(position); String taskString = item.getTask(); Date createdDate = item.getCreated(); SimpleDateFormat sdf = new SimpleDateFormat(“dd/MM/yy”); String dateString = sdf.format(createdDate); if (convertView == null) { todoView = new LinearLayout(getContext()); String inflater = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater vi; vi = (LayoutInflater)getContext().getSystemService(inflater); vi.inflate(resource, todoView, true); } else { todoView = (LinearLayout) convertView; } TextView dateView = (TextView)todoView.findViewById (R.id.rowDate); TextView taskView = (TextView)todoView.findViewById(R.id.row); dateView.setText(dateString); taskView.setText(taskString); return todoView; } }
6. 最后,用 ToDoItemAdapter 替换 ArrayAdapter 的定义。
private ToDoItemAdapter aa;
在 onCreate 中,使用 new ToDoItemAdapter 来替换 ArrayAdapter<String> 的实例化。
aa = new ToDoItemAdapter(this, resID, todoItems);
7. 如果你运行 Activity ,它看起来如图 5-4 的截图。
图 5-4
使用SimpleCursorAdapter
SimpleCursorAdapter 允许你绑定一个游标的列到 ListView 上,并使用自定义的 layout 显示每个项目。
SimpleCursorAdapter 的创建,需要传入当前的上下文、一个 layout 资源,一个游标和两个数组:一个包含使用的列的名字,另一个(相同大小)数组包含 View 中的资源 ID ,用于显示相应列的数据值。
下面的框架代码显示了如何构造一个 SimpleCursorAdapter 来显示联系人信息:
String uriString = “content://contacts/people/”; Cursor myCursor = managedQuery(Uri.parse(uriString), null, null, null, null); String[] fromColumns = new String[] { People.NUMBER, eople.NAME }; int[] toLayoutIDs = new int[] { R.id.nameTextView, R.id.numberTextView }; SimpleCursorAdapter myAdapter; myAdapter = new SimpleCursorAdapter(this,R.layout.simplecursorlayout,myCursor,fromColumns,toLayoutIDs)
SimpleCursorAdapter 在本章前面的创建选择联系人的例子中使用过。你将在第 6 章学习到更多关于 Content Provider 和 Cursor 的内容,那里你也将找到更多 SimpleCursorAdapter 的例子。