Xamarin.Android開發實踐(十二)

原文:Xamarin.Android開發實踐(十二)html

Xamarin.Android之ContentProvider

1、前言

掌握瞭如何使用SQLiteOpenHelper以後,咱們就能夠進行下一步的學習。本章咱們將會學習如何使用ContentProvider來將數據庫方面的操做封裝起來,同時它還能夠供其餘應用訪問並操做數據庫。數據庫

 

2、概念

首先咱們不會急於寫代碼,而是要搞懂如何利用ContentProvider對數 據庫進行操做,由於咱們不會直接操做數據庫對象,而是經過URI來操做數據庫。這就比如你要獲取User表的所有內容,那麼這個URI就是 content://base/user其中base是本身命名的,最好是可以惟一。由於咱們須要依靠這個區分數據庫,而後就是user是用來區分操做的 是哪一個表,固然你也能夠不用命名爲user能夠是其餘的名稱,最終反正要依靠代碼去判斷的。這樣咱們就能夠避免在活動中直接對數據庫對象操做,也方便對數 據庫進行統一的維護。框架

 

3、實際操做

 

一、搭建基本框架

新建一個LocationContentProvider類,而且繼承自ContentProvider,還要重寫該類的OnCreateDeleteGetTypeInsertQueryUpdate方法。ide

 

二、設計數據庫以及URI

下面是筆者設計好的結構:post

 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 UserTable 11 { 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_NAMEDATABASE_VERSION是數據庫的命名的和版本號,下面就是tuser表的信息,分別是表名、URI標識一、URI標識二、表結構鍵值對。UserTable類中的就是該表公開的屬性,其中包含表的字段以及查詢該表的URI路徑。咱們能夠看到該表的URI路徑爲content://xamarin-cn.location/user學習

 

三、初始化UriMatcher

咱們須要經過UriMatcher這個類來判斷URI操做的是哪一個數據庫的哪一個表,這樣就不須要咱們本身經過字符串進行判斷,具體的初始化能夠見以下代碼:ui

 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 }

 這裏咱們經過UriMatcherAddURI方法添加的不一樣類型URI,其中有針對整張表的,還有針對表中某條數據的。url

 

四、創建數據庫

這裏我就不一一介紹了直接放出代碼:spa

 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 }

 

 

5.初始化ContentProvider

首先咱們須要在OnCreate方法中將dbHelper初始化:設計

1 public override bool OnCreate() 2 { 3 dbHelper = new LocationSqliteOpenHelper(Context); 4 return true; 5 }

 

 

6.完善Query方法

爲了可以方便的組織查詢語句這裏筆者使用了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進行比較,都是同樣的只是少了一部分參數。

 

7.完善Insert

由於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 //拼接最終造成的URI 6 Android.Net.Uri result = ContentUris.WithAppendedId(UserTable.CONTENT_URI, rowId); 7 Context.ContentResolver.NotifyChange(result, null); 8 return result; 9 }

惟一要說明的就是在添加完數據以後要將這條數據組成的uri返回,這樣就能夠方便之後的查詢。

 

8.完善Update

 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 }

這裏跟查詢同樣,須要判斷是針對某條數據仍是整個表。

 

9.完善Delete

理解了Update,刪除就簡單了,只是將db.Update方法改寫成Delete便可,代碼以下所示:

 1         public override int Delete(Android.Net.Uri uri, 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.Delete(USERTABLE_NAME, selection, selectionArgs); 10  } 11 break; 12 case USER_ID: 13  { 14 String userid = uri.PathSegments.ElementAt(1); 15 string select = ""; 16 if (selection != null) 17 select = " AND(" + selection + ")"; 18 count = db.Delete(USERTABLE_NAME, 19 UserTable._ID + "=" + userid + select, 20  selectionArgs); 21  } 22 break; 23  } 24 Context.ContentResolver.NotifyChange(uri, null); 25 return count; 26 }

 最後就是GetType方法,只要返回空字符串便可。

 

4、操做ContentProvider

如今咱們回到MainActivity中使用ContentProvider對數據庫進行操做,其中最關鍵的是ContentResolver是否是跟ContentProvider是配對的?經過ContentResolver咱們就能夠經過URI來操做數據庫,而不須要關注具體的數據庫對象,好比下面的代碼咱們進行了插入、查詢、更新和刪除操做,代碼量要比使用SQLiteOpenHelper更少,同時也便於後期的維護:

 1             ContentValues values = new ContentValues();  2 values.Put(LocationContentProvider.UserTable.UserName, "yzf");  3 values.Put(LocationContentProvider.UserTable.UserPwd, "123");  4 values.Put(LocationContentProvider.UserTable.Age, 23);  5 Android.Net.Uri uri = ContentResolver.Insert(LocationContentProvider.UserTable.CONTENT_URI, values);  6  7 var c = ContentResolver.Query(uri, null, null, null, null);  8  c.MoveToFirst();  9 string username = c.GetString(c.GetColumnIndex(LocationContentProvider.UserTable.UserName)); 10 11  values.Clear(); 12 values.Put(LocationContentProvider.UserTable.UserName, "zn"); 13 ContentResolver.Update(uri, values, null, null); 14 15 c = ContentResolver.Query(uri, null, null, null, null); 16  c.MoveToFirst(); 17 username = c.GetString(c.GetColumnIndex(LocationContentProvider.UserTable.UserName)); 18 19 ContentResolver.Delete(uri, null, null);
相關文章
相關標籤/搜索