• VS/Xamarin Android开发Follow Me(十二)


    ContentProvider

    一、前言

    掌握了如何使用SQLiteOpenHelper之后,我们就可以进行下一步的学习。本章我们将会学习如何使用ContentProvider来将数据库方面的操作封装起来,同时它还可以供其他应用访问并操作数据库。

    二、概念

    首先我们不会急于写代码,而是要搞懂如何利用ContentProvider对数 据库进行操作,因为我们不会直接操作数据库对象,而是通过URI来操作数据库。这就好比你要获取User表的全部内容,那么这个URI就是 content://base/user其中base是自己命名的,最好是能够唯一。因为我们需要依靠这个区分数据库,然后就是user是用来区分操作的 是哪个表,当然你也可以不用命名为user可以是其他的名称,最终反正要依靠代码去判断的。这样我们就可以避免在活动中直接对数据库对象操作,也方便对数 据库进行统一的维护。

    三、实际操作

    1、搭建基本框架

    新建一个LocationContentProvider类,并且继承自ContentProvider,还要重写该类的OnCreateDeleteGetTypeInsertQueryUpdate方法。

    2、设计数据库以及URI

    下面是笔者设计好的结构:

     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标识1、URI标识2、表结构键值对。

    UserTable类中的就是该表公开的属性,其中包含表的字段以及查询该表的URI路径。我们可以看到该表的URI路径为content://xamarin-cn.location/user

    3、初始化UriMatcher

    我们需要通过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         }

     这里我们通过UriMatcherAddURI方法添加的不同类型URI,其中有针对整张表的,还有针对表中某条数据的。

    4、建立数据库

    这里我就不一一介绍了直接放出代码:

     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方法,只要返回空字符串即可。

    四、操作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);

     今天就到这里……

  • 相关阅读:
    思念
    Matlab与C++混合编程,添加OpenCV库
    重新启用此博客
    将博客搬至CSDN
    unity探索者之ILRuntime代码热更新
    unity探索者之UGUI圆形图片组件
    unity探索者之UGUI图片描边
    unity探索者之iOS微信登录、分享
    unity探索者之复制内容到剪贴板
    unity探索者之获取设备当前电量
  • 原文地址:https://www.cnblogs.com/xtxk110/p/12174978.html
Copyright © 2020-2023  润新知