不管是做winform的还是web的,都难免要和数据库打交道。这次我们就来探讨一下如何在MonoDroid里使用手机上的Portable数据库SQLite。数据库不外乎就是CRUD(增删改查)操作,我们来设计一个简单的数据库来放置备忘录,提醒用户还有哪些工作事项。
我们使用Menu来做数据库的增,改,删,同时搭配ListView用以查处已经增加的记录,用一个EditText作为新增或修改的录入框。
<?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"> <TextView android:id="@+id/tvInfo" android:text="按MENU可新增、修改、删除" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <EditText android:id="@+id/txtInfo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/tvInfo"/> <ListView android:id="@+id/lvInfo" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/txtInfo"> </ListView> </RelativeLayout>
在Layout目录下新建一个ListItem.axml布局文件,用于ListView中的项的布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/txtView" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
为了创建及访问数据库,我们新建一个类MySQLiteHelper,继承SQLiteOpenHelper抽象类,重写OnCreate及OnUpgrade方法,当数据库创建时,会调用OnCreate,所以可将要添加的数据库表写在里面。当更新数据库时,会调用OnUpgrade,所以可将要更新表的sql语句写在里面,同时增加增、删、改、查四个方法以供外部调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; namespace MonoDroidTest { public class MySQLiteHelper : Android.Database.Sqlite.SQLiteOpenHelper { //调用基类的构造函数,数据库名称起为MemoDb public MySQLiteHelper(Context context) : base(context, "MemoDb", null, 1) { } //在OnCreate中新建数据库表Memo,有_id字段及memoinfo字段 public override void OnCreate(Android.Database.Sqlite.SQLiteDatabase db) { string sql = "create table Memo(_id integer primary key autoincrement, memoinfo text)"; db.ExecSQL(sql); } //更新数据库时先将Memo删除再重新创建 public override void OnUpgrade(Android.Database.Sqlite.SQLiteDatabase db, int oldVersion, int newVersion) { string sql = "drop table if exists Memo"; db.ExecSQL(sql); OnCreate(db); } //查出Memo表中的数据 public Android.Database.ICursor Select() { return this.ReadableDatabase.Query("Memo", null, null, null, null, null, null); } //向Memo中插入一条新数据 public long Insert(string info) { ContentValues values = new ContentValues(); values.Put("memoinfo", info); return this.ReadableDatabase.Insert("Memo", null, values); } //删除Memo中一条记录 public void Delete(int id) { this.ReadableDatabase.Delete("Memo", "_id=?", new string[] { id.ToString() }); } //根据id修改Memo的记录 public void Update(int id, string info) { ContentValues values = new ContentValues(); values.Put("memoinfo", info); this.ReadableDatabase.Update("Memo", values, "_id=?", new string[] { id.ToString() }); } } }
在Activity1中添加三个menu作为新增,修改和删除,在Menu的点击选择事件ItemSelected中调用MySQLiteHelper来访问数据库,当单击ListView时,可将选择的数据带入上方的EditText做修改,做完增删改操作后,立即更新下方的ListView。若EditText里的值为空时,则不添加到数据库。
[Activity(Label = "MonoDroidTest", MainLauncher = true)] public class Activity1 : Activity { int id; ListView lvInfo; EditText txtInfo; MySQLiteHelper db; ICursor cur; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.Main); try { lvInfo = FindViewById<ListView>(Resource.Id.lvInfo); txtInfo = FindViewById<EditText>(Resource.Id.txtInfo); db = new MySQLiteHelper(this); cur = db.Select(); SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, Resource.Layout.ListItem, cur, new string[] { "memoinfo" }, new int[] { Resource.Id.txtView }); lvInfo.Adapter = adapter; lvInfo.ItemClick += (sender, e) => { cur.MoveToPosition(e.Position); id = cur.GetInt(0); txtInfo.Text = cur.GetString(1); }; lvInfo.ItemSelected += (sender, e) => { SQLiteCursor sc = (sender as AdapterView).SelectedItem as SQLiteCursor; id = sc.GetInt(0); txtInfo.Text = sc.GetString(1); }; } catch (System.Exception ex) { MessageBox.ShowErrorMessage(this, ex); } } private const int NONE = MenuConsts.None; private const int MENU_ADD = MenuConsts.First; private const int MENU_EDIT = MenuConsts.First + 1; private const int MENU_DELETE = MenuConsts.First + 2; public override bool OnCreateOptionsMenu(IMenu menu) { menu.Add(NONE, MENU_ADD, 0, new Java.Lang.String("新增")); menu.Add(NONE, MENU_EDIT, 1, new Java.Lang.String("修改")); menu.Add(NONE, MENU_DELETE, 2, new Java.Lang.String("删除")); return base.OnCreateOptionsMenu(menu); } public override bool OnOptionsItemSelected(IMenuItem item) { bool b = base.OnOptionsItemSelected(item); switch (item.ItemId) { case MENU_ADD: Add(); break; case MENU_EDIT: Edit(); break; case MENU_DELETE: Delete(); break; } return b; } private void Add() { if (string.IsNullOrEmpty(txtInfo.Text)) return; db.Insert(txtInfo.Text); Init(); } private void Edit() { if (string.IsNullOrEmpty(txtInfo.Text) || id == 0) return; try { db.Update(id, txtInfo.Text); Init(); } catch (System.Exception ex) { MessageBox.ShowErrorMessage(this, ex); } } private void Delete() { if (id == 0) return; db.Delete(id); Init(); } private void Init() { cur.Requery(); lvInfo.InvalidateViews(); txtInfo.Text = ""; id = 0; } }
使用SimpleCursorAdapter来做ListView的adapter,将Cursor及要显示的字段名称传入,就会产生想要显示的数据的ListView。另外值得注意的一点是,使用SimpleCursorAdapter所设计的数据表一定要有_id这个字段名称,否则会抛出“找不到_id字段”的异常。