掌握了如何使用SQLiteOpenHelper之后,我们就可以进行下一步的学习。本章我们将会学习如何使用ContentProvider来将数据库方面的操作封装起来,同时它还可以供其他应用访问并操作数据库。
首先我们不会急于写代码,而是要搞懂如何利用ContentProvider对数据库进行操作,因为我们不会直接操作数据库对象,而是通过URI来操作数据库。这就好比你要获取User表的全部内容,那么这个URI就是content://base/user其中base是自己命名的,最好是能够唯一。因为我们需要依靠这个区分数据库,然后就是user是用来区分操作的是哪个表,当然你也可以不用命名为user可以是其他的名称,最终反正要依靠代码去判断的。这样我们就可以避免在活动中直接对数据库对象操作,也方便对数据库进行统一的维护。
新建一个LocationContentProvider类,并且继承自ContentProvider,还要重写该类的OnCreate、Delete、GetType、Insert、Query和Update方法。
下面是笔者设计好的结构:
1 public static string PROVIDER_NAME = "xamarin-cn.location"; 2 3 private const string DATABASE_NAME = "location"; 4 private const int DATABASE_VERSION = 1; 5 6 private const string USERTABLE_NAME = "tuser"; 7 private const int USER = 1; 8 private const int USER_ID = 2; 9 private static IDictionary<string, string> userProjectionMap;10 public class UserTable11 {12 public static Android.Net.Uri CONTENT_URI = Android.Net.Uri.Parse("content://" + PROVIDER_NAME + "/user");13 public const string _ID = "_id";14 public const string UserName = "username";15 public const string UserPwd = "userpwd";16 public const string Age = "age";17 }其中 PROVIDER_NAME 是URI的基址,DATABASE_NAME和DATABASE_VERSION是数据库的命名的和版本号,下面就是tuser表的信息,分别是表名、URI标识1、URI标识2、表结构键值对。UserTable类中的就是该表公开的属性,其中包含表的字段以及查询该表的URI路径。我们可以看到该表的URI路径为content://xamarin-cn.location/user。
我们需要通过UriMatcher这个类来判断URI操作的是哪个数据库的哪个表,这样就不需要我们自己通过字符串进行判断,具体的初始化可以见如下代码:
1 private static UriMatcher uriMatcher; 2 static LocationContentProvider() 3 { 4 userProjectionMap = new Dictionary<string, string>(); 5 userProjectionMap.Add(UserTable._ID, UserTable._ID); 6 userProjectionMap.Add(UserTable.UserName, UserTable.UserName); 7 userProjectionMap.Add(UserTable.UserPwd, UserTable.UserPwd); 8 userProjectionMap.Add(UserTable.Age, UserTable.Age); 9 uriMatcher = new UriMatcher(UriMatcher.NoMatch);10 uriMatcher.AddURI(PROVIDER_NAME, "user", USER);11 uriMatcher.AddURI(PROVIDER_NAME, "user/#", USER_ID);12 }这里我们通过UriMatcher的AddURI方法添加的不同类型URI,其中有针对整张表的,还有针对表中某条数据的。
这里我就不一一介绍了直接放出代码:
1 private LocationSqliteOpenHelper dbHelper; 2 class LocationSqliteOpenHelper : SQLiteOpenHelper 3 { 4 public LocationSqliteOpenHelper(Context context) 5 : base(context, DATABASE_NAME, null, DATABASE_VERSION) 6 { 7 } 8 9 public override void OnCreate(SQLiteDatabase db)10 {11 StringBuilder strSql = new StringBuilder();12 strSql.AppendFormat("CREATE TABLE {0} (", USERTABLE_NAME);13 strSql.AppendFormat("{0} INTEGER PRIMARY KEY NOT NULL,", UserTable._ID);14 strSql.AppendFormat("{0} TEXT NOT NULL,", UserTable.UserName);15 strSql.AppendFormat("{0} TEXT NOT NULL,", UserTable.UserPwd);16 strSql.AppendFormat("{0} INTEGER NOT NULL)", UserTable.Age);17 db.ExecSQL(strSql.ToString());18 }19 20 public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)21 {22 db.ExecSQL("DROP TABLE IF EXISTS " + USERTABLE_NAME);23 OnCreate(db);24 }25 }首先我们需要在OnCreate方法中将dbHelper初始化:
1 public override bool OnCreate()2 {3 dbHelper = new LocationSqliteOpenHelper(Context);4 return true;5 }为了能够方便的组织查询语句这里笔者使用了SQLiteQueryBuilder对象来组织,下面就是查询的代码:
1 public override Android.Database.ICursor Query(Android.Net.Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder) 2 { 3 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 4 qb.Tables = USERTABLE_NAME; 5 //根据uri判断查询的是某条数据还是针对整个表,从而决定条件语句 6 switch (uriMatcher.Match(uri)) 7 { 8 case USER: 9 {10 //设置需要获取的字段11 //userProjectionMap默认包含的所有字段12 qb.SetProjectionMap(userProjectionMap);13 }14 break;15 case USER_ID:16 {17 qb.SetProjectionMap(userProjectionMap);18 //拼接条件语句19 //其中uri.PathSegments.ElementAt(1) 将会获取第二个片段,20 //就是第二个“/”后台的内容,如果后面还存在“/”则获取他们之间的内容21 qb.AppendWhere(UserTable._ID + "=" + uri.PathSegments.ElementAt(1));22 }23 break;24 }25 SQLiteDatabase db = dbHelper.ReadableDatabase;26 ICursor c = qb.Query(db, projection, selection, selectionArgs, null, null, " _id desc");27 c.SetNotificationUri(Context.ContentResolver, uri);28 return c;29 }代码中的注释已经将重点部分都介绍了,关于Query的参数可以跟数据库对象的Query进行比较,都是一样的只是少了一部分参数。
因为SQLite规定了id只能是数据库自动生成的,所以在插入数据库这块只需要判断操作的是哪个表,介于笔者这里只有一个表所以没有该项操作,下面是具体的代码:
1 public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)2 {3 SQLiteDatabase db = dbHelper.WritableDatabase;4 long rowId = db.Insert(USERTABLE_NAME, null, values);5 //拼接最终形成的URI6 Android.Net.Uri result = ContentUris.WithAppendedId(UserTable.CONTENT_URI, rowId);7 Context.ContentResolver.NotifyChange(result, null);8 return result;9 }唯一要说明的就是在添加完数据之后要将这条数据组成的uri返回,这样就可以方便以后的查询。
1 public override int Update(Android.Net.Uri uri, ContentValues values, string selection, string[] selectionArgs) 2 { 3 SQLiteDatabase db = dbHelper.WritableDatabase; 4 int count = 0; 5 switch (uriMatcher.Match(uri)) 6 { 7 case USER: 8 { 9 count = db.Update(USERTABLE_NAME, values, selection, selectionArgs);10 }11 break;12 case USER_ID:13 {14 String userid = uri.PathSegments.ElementAt(1);15 string select = "";16 //如果还有附加的查询语句则拼接上去17 if (selection != null)18 select = " AND(" + selection + ")";19 count = db.Update(USERTABLE_NAME, values, UserTable._ID + "=" + userid + select, selectionArgs);20 }21 break;22 }23 Context.ContentResolver.NotifyChange(uri, null);24 return count;25 }这里跟查询一样,需要判断是针对某条数据还是整个表。
理解了Update,删除就简单了,只是将db.Update方法改写成Delete即可,代码如下所示:
1 public override int Delete(Android.Net.Uri uri, string selection, string[] selectionArgs) 2 { 3 SQLiteDatabase db = dbHelper.Writa
新闻热点
疑难解答
图片精选