一、前言

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

二、概念

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

三、实际操作

1、搭建基本框架

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

2、设计数据库以及URI

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

 public static string PROVIDER_NAME = "xamarin-cn.location";

 private const string DATABASE_NAME = "location";
private const int DATABASE_VERSION = ; private const string USERTABLE_NAME = "tuser";
private const int USER = ;
private const int USER_ID = ;
private static IDictionary<string, string> userProjectionMap;
public class UserTable
{
public static Android.Net.Uri CONTENT_URI = Android.Net.Uri.Parse("content://" + PROVIDER_NAME + "/user");
public const string _ID = "_id";
public const string UserName = "username";
public const string UserPwd = "userpwd";
public const string Age = "age";
}

其中 PROVIDER_NAME 是URI的基址,DATABASE_NAMEDATABASE_VERSION是数据库的命名的和版本号,下面就是tuser表的信息,分别是表名、URI标识1、URI标识2、表结构键值对。UserTable类中的就是该表公开的属性,其中包含表的字段以及查询该表的URI路径。我们可以看到该表的URI路径为content://xamarin-cn.location/user

3、初始化UriMatcher

我们需要通过UriMatcher这个类来判断URI操作的是哪个数据库的哪个表,这样就不需要我们自己通过字符串进行判断,具体的初始化可以见如下代码:

         private static UriMatcher uriMatcher;
static LocationContentProvider()
{
userProjectionMap = new Dictionary<string, string>();
userProjectionMap.Add(UserTable._ID, UserTable._ID);
userProjectionMap.Add(UserTable.UserName, UserTable.UserName);
userProjectionMap.Add(UserTable.UserPwd, UserTable.UserPwd);
userProjectionMap.Add(UserTable.Age, UserTable.Age);
uriMatcher = new UriMatcher(UriMatcher.NoMatch);
uriMatcher.AddURI(PROVIDER_NAME, "user", USER);
uriMatcher.AddURI(PROVIDER_NAME, "user/#", USER_ID);
}

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

4、建立数据库

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

         private LocationSqliteOpenHelper dbHelper;
class LocationSqliteOpenHelper : SQLiteOpenHelper
{
public LocationSqliteOpenHelper(Context context)
: base(context, DATABASE_NAME, null, DATABASE_VERSION)
{
} public override void OnCreate(SQLiteDatabase db)
{
StringBuilder strSql = new StringBuilder();
strSql.AppendFormat("CREATE TABLE {0} (", USERTABLE_NAME);
strSql.AppendFormat("{0} INTEGER PRIMARY KEY NOT NULL,", UserTable._ID);
strSql.AppendFormat("{0} TEXT NOT NULL,", UserTable.UserName);
strSql.AppendFormat("{0} TEXT NOT NULL,", UserTable.UserPwd);
strSql.AppendFormat("{0} INTEGER NOT NULL)", UserTable.Age);
db.ExecSQL(strSql.ToString());
} public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.ExecSQL("DROP TABLE IF EXISTS " + USERTABLE_NAME);
OnCreate(db);
}
}

5.初始化ContentProvider

首先我们需要在OnCreate方法中将dbHelper初始化:

 public override bool OnCreate()
{
dbHelper = new LocationSqliteOpenHelper(Context);
return true;
}

6.完善Query方法

为了能够方便的组织查询语句这里笔者使用了SQLiteQueryBuilder对象来组织,下面就是查询的代码:

         public override Android.Database.ICursor Query(Android.Net.Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder)
{
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.Tables = USERTABLE_NAME;
//根据uri判断查询的是某条数据还是针对整个表,从而决定条件语句
switch (uriMatcher.Match(uri))
{
case USER:
{
//设置需要获取的字段
//userProjectionMap默认包含的所有字段
qb.SetProjectionMap(userProjectionMap);
}
break;
case USER_ID:
{
qb.SetProjectionMap(userProjectionMap);
//拼接条件语句
//其中uri.PathSegments.ElementAt(1) 将会获取第二个片段,
//就是第二个“/”后台的内容,如果后面还存在“/”则获取他们之间的内容
qb.AppendWhere(UserTable._ID + "=" + uri.PathSegments.ElementAt());
}
break;
}
SQLiteDatabase db = dbHelper.ReadableDatabase;
ICursor c = qb.Query(db, projection, selection, selectionArgs, null, null, " _id desc");
c.SetNotificationUri(Context.ContentResolver, uri);
return c;
}

代码中的注释已经将重点部分都介绍了,关于Query的参数可以跟数据库对象的Query进行比较,都是一样的只是少了一部分参数。

7.完善Insert

因为SQLite规定了id只能是数据库自动生成的,所以在插入数据库这块只需要判断操作的是哪个表,介于笔者这里只有一个表所以没有该项操作,下面是具体的代码:

         public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)
{
SQLiteDatabase db = dbHelper.WritableDatabase;
long rowId = db.Insert(USERTABLE_NAME, null, values);
//拼接最终形成的URI
Android.Net.Uri result = ContentUris.WithAppendedId(UserTable.CONTENT_URI, rowId);
Context.ContentResolver.NotifyChange(result, null);
return result;
}

唯一要说明的就是在添加完数据之后要将这条数据组成的uri返回,这样就可以方便以后的查询。

8.完善Update

         public override int Update(Android.Net.Uri uri, ContentValues values, string selection, string[] selectionArgs)
{
SQLiteDatabase db = dbHelper.WritableDatabase;
int count = ;
switch (uriMatcher.Match(uri))
{
case USER:
{
count = db.Update(USERTABLE_NAME, values, selection, selectionArgs);
}
break;
case USER_ID:
{
String userid = uri.PathSegments.ElementAt();
string select = "";
//如果还有附加的查询语句则拼接上去
if (selection != null)
select = " AND(" + selection + ")";
count = db.Update(USERTABLE_NAME, values, UserTable._ID + "=" + userid + select, selectionArgs);
}
break;
}
Context.ContentResolver.NotifyChange(uri, null);
return count;
}

这里跟查询一样,需要判断是针对某条数据还是整个表。

9.完善Delete

理解了Update,删除就简单了,只是将db.Update方法改写成Delete即可,代码如下所示:

         public override int Delete(Android.Net.Uri uri, string selection, string[] selectionArgs)
{
SQLiteDatabase db = dbHelper.WritableDatabase;
int count = ;
switch (uriMatcher.Match(uri))
{
case USER:
{
count = db.Delete(USERTABLE_NAME, selection, selectionArgs);
}
break;
case USER_ID:
{
String userid = uri.PathSegments.ElementAt();
string select = "";
if (selection != null)
select = " AND(" + selection + ")";
count = db.Delete(USERTABLE_NAME,
UserTable._ID + "=" + userid + select,
selectionArgs);
}
break;
}
Context.ContentResolver.NotifyChange(uri, null);
return count;
}

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

四、操作ContentProvider

现在我们回到MainActivity中使用ContentProvider对数据库进行操作,其中最关键的是ContentResolver是不是跟ContentProvider是配对的?通过ContentResolver我们就可以通过URI来操作数据库,而不需要关注具体的数据库对象,比如下面的代码我们进行了插入、查询、更新和删除操作,代码量要比使用SQLiteOpenHelper更少,同时也便于后期的维护:

             ContentValues values = new ContentValues();
values.Put(LocationContentProvider.UserTable.UserName, "yzf");
values.Put(LocationContentProvider.UserTable.UserPwd, "");
values.Put(LocationContentProvider.UserTable.Age, );
Android.Net.Uri uri = ContentResolver.Insert(LocationContentProvider.UserTable.CONTENT_URI, values); var c = ContentResolver.Query(uri, null, null, null, null);
c.MoveToFirst();
string username = c.GetString(c.GetColumnIndex(LocationContentProvider.UserTable.UserName)); values.Clear();
values.Put(LocationContentProvider.UserTable.UserName, "zn");
ContentResolver.Update(uri, values, null, null); c = ContentResolver.Query(uri, null, null, null, null);
c.MoveToFirst();
username = c.GetString(c.GetColumnIndex(LocationContentProvider.UserTable.UserName)); ContentResolver.Delete(uri, null, null);

示例项目下载请点我

Xamarin.Android之ContentProvider的更多相关文章

  1. Xamarin.Android开发实践(十四)

    Xamarin.Android之ListView和Adapter 一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xamarin去实现它,以及如何使用适配器和自定义适配器(本文 ...

  2. Xamarin.Android开发实践(十三)

    Xamarin.Android之SQLite.NET ORM 一.前言 通过<Xamarin.Android之SQLiteOpenHelper>和<Xamarin.Android之C ...

  3. Xamarin.Android开发实践(十二)

    Xamarin.Android之ContentProvider 一.前言 掌握了如何使用SQLiteOpenHelper之后,我们就可以进行下一步的学习.本章我们将会学习如何使用ContentProv ...

  4. Xamarin.Android之ListView和Adapter

    一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xamarin去实现它,以及如何使用适配器和自定义适配器(本文中的适配器的主要内容就是将原始的数据转换成了能够供列表控件显示的项 ...

  5. Xamarin.Android之SQLite.NET ORM

    一.前言 通过<Xamarin.Android之SQLiteOpenHelper>和<Xamarin.Android之ContentProvider>的学习,我们已经掌握了如何 ...

  6. XAMARIN.ANDROID SIGNALR 实时消息接收发送示例

    SignalR 是一个开发实时 Web 应用的 .NET 类库,使用 SignalR 可以很容易的构建基于 ASP.NET 的实时 Web 应用.SignalR 支持多种服务器和客户端,可以 Host ...

  7. Android之ContentProvider数据存储

    一.ContentProvider保存数据介绍 一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数 ...

  8. XAMARIN ANDROID 二维码扫描示例

    现在二维码的应用越来越普及,二维码扫描也成为手机应用程序的必备功能了.本文将基于 Xamarin.Android 平台使用 ZXing.Net.Mobile  做一个简单的 Android 条码扫描示 ...

  9. 我正在使用Xamarin的跨平台框架—Xamarin.Android回忆录

    一.缘起 在自己给别家公司做兼职外包的时候,已经明确知道外包的活不是那么好干的,一般在经历了初期热血澎湃的激情后,逐渐冷淡,愤怒,再冷淡,再愤怒…,听上去好像高潮迭起,但令人尴尬的是,这高潮迭起我们都 ...

随机推荐

  1. 02.LoT.UI 前后台通用框架分解系列之——灵活的菜单栏

    LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...

  2. 立即执行函数表达式(IIFE)

    原文地址:benalman.com/news/2010/11/immediately-invoked-function-expression/ 译者:nzbin 也许你还没有注意到,我是一个对术语比较 ...

  3. 从netty-example分析Netty组件续

    上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...

  4. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  5. 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)

    很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...

  6. iOS controller解耦探究实现——第一次写博客

    大学时曾经做过android的开发,目前的工作是iOS的开发.之前自己记录东西都是通过自己比较喜欢的笔记类的应用记录下了.直到前段时一个哥们拉着我注册了一个博客.现在终于想明白了,博客这个东西受众会稍 ...

  7. YII 2.x 模板文件的 beginBlock、beginContent、beginCache

    echo '-----------beginBlock--------------------- <br />'; $this->beginBlock('block1', false ...

  8. celery使用的一些小坑和技巧(非从无到有的过程)

    纯粹是记录一下自己在刚开始使用的时候遇到的一些坑,以及自己是怎样通过配合redis来解决问题的.文章分为三个部分,一是怎样跑起来,并且怎样监控相关的队列和任务:二是遇到的几个坑:三是给一些自己配合re ...

  9. GOF23设计模式归类

    创建型模式:-单例模式.工厂模式.抽象工厂模式.建造者模式.原型模式结构型模式:-适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式行为型模式:-模板方法模式.命令模式.迭代器模式 ...

  10. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...