将 CursorAdapters 与 Xamarin.Android 配合使用

Android 专门提供了适配器类来显示 SQLite 数据库查询中的数据:

SimpleCursorAdapter – 类似于 ArrayAdapter,因为它可以在不子类化的情况下使用。 只需在构造函数中提供所需的参数(如游标和布局信息),然后分配给一个 ListView

CursorAdapter – 一个基类,当需要对将数据值绑定到布局控件进行更多控制时(例如隐藏/显示控件或更改其属性),可以继承该基类。

游标适配器提供了一种高性能方法,用于滚动浏览存储在 SQLite 中的数据的长列表。 使用的代码必须在 Cursor 对象中定义 SQL 查询,然后描述如何为每个行创建和填充视图。

创建 SQLite 数据库

若要演示游标适配器,需要一个简单的 SQLite 数据库实现。 SimpleCursorTableAdapter/VegetableDatabase.cs 中的代码包含用于创建表并使用某些数据填充表的代码和 SQL。 完整的 VegetableDatabase 类如下所示:

class VegetableDatabase  : SQLiteOpenHelper {
   public static readonly string create_table_sql =
       "CREATE TABLE [vegetables] ([_id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, [name] TEXT NOT NULL UNIQUE)";
   public static readonly string DatabaseName = "vegetables.db";
   public static readonly int DatabaseVersion = 1;
   public VegetableDatabase(Context context) : base(context, DatabaseName, null, DatabaseVersion) { }
   public override void OnCreate(SQLiteDatabase db)
   {
       db.ExecSQL(create_table_sql);
       // seed with data
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Vegetables')");
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Fruits')");
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Flower Buds')");
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Legumes')");
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Bulbs')");
       db.ExecSQL("INSERT INTO vegetables (name) VALUES ('Tubers')");
   }
   public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
   {   // not required until second version :)
       throw new NotImplementedException();
   }
}

VegetableDatabase 类将在 HomeScreen 活动的 OnCreate 方法中实例化。 SQLiteOpenHelper 基类管理数据库文件的设置,并确保其 OnCreate 方法中的 SQL 仅运行一次。 此类在以下两个示例中用于 SimpleCursorAdapterCursorAdapter

游标查询必须具有一个整数列 _id 才能使 CursorAdapter 正常工作。 如果基础表没有名为 _id 的整数列,则对构成游标的 RawQuery 中另一个唯一整数使用列别名。 有关详细信息,请参阅 Android 文档

创建游标

这些示例使用 RawQuery 将 SQL 查询转换为 Cursor 对象。 从游标返回的列列表定义可用于在游标适配器中显示的数据列。 此处显示了在 SimpleCursorTableAdapter/HomeScreen.csOnCreate 方法中创建数据库的代码:

vdb = new VegetableDatabase(this);
cursor = vdb.ReadableDatabase.RawQuery("SELECT * FROM vegetables", null); // cursor query
StartManagingCursor(cursor);
// use either SimpleCursorAdapter or CursorAdapter subclass here!

调用 StartManagingCursor 的任何代码也应调用 StopManagingCursor。 这些示例使用 OnCreate 启动游标,使用 OnDestroy 关闭游标。 OnDestroy 方法包含以下代码:

StopManagingCursor(cursor);
cursor.Close();

一旦应用程序具有可用的 SQLite 数据库并已创建所示的游标对象,它就可以利用 SimpleCursorAdapterCusorAdapter 的子类来显示 ListView 中的行。

使用 SimpleCursorAdapter

SimpleCursorAdapter 就像 ArrayAdapter,但它专用于 SQLite。 它不需要子类化 – 只需在创建对象时设置一些简单参数,然后将其分配给 ListViewAdapter 属性。

SimpleCursorAdapter 构造函数的参数包括:

Context – 对包含活动的引用。

Layout – 要使用的行视图的资源 ID。

ICursor – 包含使数据显示的 SQLite 查询的游标。

From 字符串数组 – 对应于游标中列名称的字符串数组。

To 整数数组 – 与行布局中的控件对应的布局 ID 的数组。 from 数组中指定的列的值将绑定到此数组中指定的同一索引处的 ControlID。

fromto 数组必须具有相同数量的条目,因为它们构成了从数据源到视图中布局控件的映射。

SimpleCursorTableAdapter/HomeScreen.cs 示例代码连接 SimpleCursorAdapter 的方式如下:

// which columns map to which layout controls
string[] fromColumns = new string[] {"name"};
int[] toControlIDs = new int[] {Android.Resource.Id.Text1};
// use a SimpleCursorAdapter
listView.Adapter = new SimpleCursorAdapter (this, Android.Resource.Layout.SimpleListItem1, cursor,
       fromColumns,
       toControlIDs);

SimpleCursorAdapter 是一种在 ListView 中显示 SQLite 数据的快速简单方法。 主要局限是它只能绑定列值以显示控件,它不允许更改行布局的其他方面(例如,显示/隐藏控件或更改属性)。

子类化 CursorAdapter

在显示 SQLite 中的数据方面,CursorAdapter 子类的性能优势与 SimpleCursorAdapter 相同,但它还让你能够完全控制每个行视图的创建和布局。 CursorAdapter 实现与子类化 BaseAdapter 大不相同,因为它不会替代 GetViewGetItemIdCountthis[] 索引器。

给定一个工作 SQLite 数据库,只需替代两个方法来创建 CursorAdapter 子类:

  • BindView – 给定一个视图,更新它以显示所提供的游标中的数据。

  • NewView – 当 ListView 需要显示新视图时调用。 CursorAdapter 将处理视图回收(与常规适配器上的 GetView 方法不同)。

前面的示例中的适配器子类具有返回行数和检索当前项的方法 – CursorAdapter 不需要这些方法,因为可以从游标本身收集该信息。 通过将每个视图的创建和填充拆分为这两个方法,CursorAdapter 强制重用视图。 这与常规适配器形成鲜明对比,常规适配器可以忽略 BaseAdapter.GetView 方法的 convertView 参数。

实现 CursorAdapter

CursorTableAdapter/HomeScreenCursorAdapter.cs 中的代码包含 CursorAdapter 子类。 它存储传入构造函数的上下文引用,以便它可以访问 NewView 方法中的 LayoutInflater。 完整的类如下所示:

public class HomeScreenCursorAdapter : CursorAdapter {
   Activity context;
   public HomeScreenCursorAdapter(Activity context, ICursor c)
       : base(context, c)
   {
       this.context = context;
   }
   public override void BindView(View view, Context context, ICursor cursor)
   {
       var textView = view.FindViewById<TextView>(Android.Resource.Id.Text1);
       textView.Text = cursor.GetString(1); // 'name' is column 1 in the cursor query
   }
   public override View NewView(Context context, ICursor cursor, ViewGroup parent)
   {
       return this.context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, parent, false);
   }
}

分配 CursorAdapter

在将显示 ListViewActivity 中,创建游标,然后 CursorAdapter 将其分配给列表视图。

CursorTableAdapter/HomeScreen.csOnCreate 方法中执行此操作的代码如下所示:

// create the cursor
vdb = new VegetableDatabase(this);
cursor = vdb.ReadableDatabase.RawQuery("SELECT * FROM vegetables", null);
StartManagingCursor(cursor);

// create the CursorAdapter
listView.Adapter = (IListAdapter)new HomeScreenCursorAdapter(this, cursor, false);

OnDestroy 方法包含前面所述的 StopManagingCursor 方法调用。