Xamarin.Android开发实践(十二)

原文:Xamarin.Android开发实践(十二)

Xamarin.Android之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);

 

时间: 2024-09-17 09:32:56

Xamarin.Android开发实践(十二)的相关文章

Xamarin.Android开发实践(二)

原文:Xamarin.Android开发实践(二) 一.准备 开始学习本教程前必须先完成该教程http://www.cnblogs.com/yaozhenfa/p/xamarin_android_quickstart.html 否则将无法继续.   二.界面 1.打开Resources/layout/Main.axml文件,并在Call Button下方继续加入一个按钮,并设置其id为@+id/CallHistoryButton同时设置Text为@string /callHistory(这个其实

Xamarin.Android开发实践(十八)

原文:Xamarin.Android开发实践(十八) Xamarin.Android之SlidingMenu 一.前言 有位网友在评论中希望能够出个在Xamarin.Android下实现SlidingMenu效果的随笔,刚好昨天在观看官网示例项目的时候也看到这个SlidingMenu,但是最终的效果并不是我们所期待的,至此笔者就在官方的论坛中寻找,最后也成功的寻找到的答案,下面笔者将带领带领大家实现SlidingMenu.   二.准备工作 实现SlidingMenu重点是需要一个第三方的类库,

Xamarin.Android开发实践(十四)

原文:Xamarin.Android开发实践(十四) Xamarin.Android之ListView和Adapter 一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xamarin去实现它,以及如何使用适配器和自定义适配器(本文中的适配器的主要内容就是将原始的数据转换成了能够供列表控件显示的项).   二.简介适配器 在开始之前我们需要先了解下适配器,首先是提供给我们使用的适配器之间的关系: 下面我们将上面的适配器进行简单的介绍: BaseAdapter:顾名思义,就是

Xamarin.Android开发实践(十)

原文:Xamarin.Android开发实践(十) Xamarin.Android之SQLiteOpenHelper 一.前言 在手机中进行网络连接不仅是耗时也是耗电的,而耗电却是致命的.所以我们就需要数 据库帮助我们存储离线数据,以便在用户未使用网络的情况下也可以能够使用应用的部分功能,而在需要网络连接的功能上采用提示方式,让用户决定是否打开网 络.而本节我们将会学习如何访问数据库以及提供基本的增删改查功能,并且使他们尽量的解耦.   二.数据库 Xamarin.Android下创建本地数据库

Xamarin.Android开发实践(十五)

原文:Xamarin.Android开发实践(十五) Xamarin.Android学习之应用程序首选项 一.前言 任何App都会存在设置界面,如果开发者利用普通控件并绑定监听事件保存设置,这 一过程会非常的枯燥,而且耗时.我们可以看到Android系统的设置界面里面的选项如此之多,是不是都是这样开发的呢?其实不然,Android已经给 我们提供了专门设计这一功能的技术,叫应用程序首选项,今天我们将学习如何使用他们来开发配置界面以及功能.   二.准备工作 首先需要理解的就是我们设置界面还是需要

Xamarin.Android开发实践(十六)

原文:Xamarin.Android开发实践(十六) Xamarin.Android之Fragment Walkthrough 利用Fragment设计能够兼容不同屏幕的应用 这里我们先围观下最后的成果图,给读者打打气:   普通手机上显示的结果:   在平板上显示的结果:   笔者要郑重声明下,虽然看似是两种不同的显示效果,但是同一个应用,而下面笔者将逐步教会大家如何利用Fragment制作出能够兼容不同屏幕的应用.   准备工作 创建一个项目是必不可少的,并且Android SDK的版本要在

Xamarin.Android开发实践(六)

原文:Xamarin.Android开发实践(六) Xamarin.Android通知详解 一.发送通知的机制 在日常的app应用中经常需要使用通知,因为服务.广播后台活动如果有事件需要通知用户,则需要通过通知栏显示,而在Xamarin.Android下的通知需要获取NotificationManager服务,而该服务需要通过GetSystemService获取,同时还要传递一个标识符.获取了通知管理器后我们就可以实例化Notification,然后再由NotificationManager发送

Xamarin.Android开发实践(九)

原文:Xamarin.Android开发实践(九) Xamarin.Android之ActionBar与菜单 一.选项卡 如今很多应用都会使用碎片以便在同一个活动中能够显示多个不同的视图.在 Android 3.0 以上的版本中,我们已经可以使用ActionBar提供的Tab来实现这种效果,而不需要我们自己去实现碎片的切换.ActionBar默认是不具备选项 卡功能的,所以我们需要给一个属性赋上对应的枚举,比如下面的方式将开启选项卡. 1 ActionBar.NavigationMode = A

Xamarin.Android开发实践(十七)

原文:Xamarin.Android开发实践(十七) Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定位,从而使我们的生活更加方便,所以本章我们将学习如何在Xamarin中进行定位的开发.     二.准备工作 因为我们的虚拟机是运行在电脑本地的,自然就没法进行定位了,但是我们可以借助DDMS这个工具帮助我们去调试.   首先要确定你的Android SDK所在的目录,读者可以通过以下方式找到: 工具->选项   然后读者打开该文件夹下的tool