ContentProvider数据库共享之——实例讲解
前言:现在这段时间没这么忙了,要抓紧时间把要总结的知识沉淀下来,今年重新分了项目组,在新项目中应该不会那么忙了,看来有时间来学一些自己的东西了。现在而言,我需要的是时间。只要不断的努力,总有一天,你会与从不同。加油。
相关文章:
1、《ContentProvider数据库共享之——概述》
2、《ContentProvider数据库共享之——实例讲解》
3、《ContentProvider数据库共享之——MIME类型与getType()》
4、《ContentProvider数据库共享之——读写权限与数据监听》
在上篇文章中,已经给大家初步讲解了有关ContentProvder的整体流程及设计方式,在这篇文章中将通过实例来讲述ContentProvider的操作过程;
一、ContentProvider提供数据库查询接口
在上篇中,我们提到过,两个应用间是通过Content URI来媒介传递消息的,我们的应用在收到URI以后,通过匹配完成对应的数据库操作功能。听的有点迷糊?没关系,下面会细讲,我这里要说的是,匹配成功后要完成的数据库操作!!!那好,我们的第一步:建数据库,数据表
1、利用SQLiteOpenHelper创建数据库、数据表
在这里,我们在一个数据库(“harvic.db”)中创建两个数据表”first”与”second”;每个表都有多出一个字段“table_name”,来保存当前数据表的名称
代码如下:
- public class DatabaseHelper extends SQLiteOpenHelper {
- public static final String DATABASE_NAME = "harvic.db";
- public static final int DATABASE_VERSION = 1;
- public static final String TABLE_FIRST_NAME = "first";
- public static final String TABLE_SECOND_NAME = "second";
- public static final String SQL_CREATE_TABLE_FIRST = "CREATE TABLE " +TABLE_FIRST_NAME +"("
- + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + "table_name" +" VARCHAR(50) default 'first',"
- + "name" + " VARCHAR(50),"
- + "detail" + " TEXT"
- + ");" ;
- public static final String SQL_CREATE_TABLE_SECOND = "CREATE TABLE "+TABLE_SECOND_NAME+" ("
- + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + "table_name" +" VARCHAR(50) default 'second',"
- + "name" + " VARCHAR(50),"
- + "detail" + " TEXT"
- + ");" ;
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
- @Override
- public void onCreate(SQLiteDatabase db) {
- Log.e("harvic", "create table: " + SQL_CREATE_TABLE_FIRST);
- db.execSQL(SQL_CREATE_TABLE_FIRST);
- db.execSQL(SQL_CREATE_TABLE_SECOND);
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE IF EXISTS first");
- db.execSQL("DROP TABLE IF EXISTS second");
- onCreate(db);
- }
- }
2、利用ContentProvider提供数据库操作接口
新建一个类PeopleContentProvider,派生自ContentProvider基类,写好之后,就会自动生成query(),insert(),update(),delete()和getType()方法;这些方法就是根据传过来的URI来操作数据库的接口。此时的PeopleContentProvider是这样的:
- public class PeopleContentProvider extends ContentProvider {
- @Override
- public boolean onCreate() {
- return false;
- }
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
- return null;
- }
- @Override
- public String getType(Uri uri) {
- return null;
- }
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
- }
3、使用UriMatcher匹配URI
我们先不管这几个函数的具体操作,先想想在上节中我提到的当一个URI逐级匹配到了ContentProvider类里以后,会怎么做——利用UriMatcher进行再次匹配!!!UriMatcher匹配成功以后,才会执行对应的操作。所以上面的那些操作是在UriMatcher匹配之后。
好,我们就先看看UriMatcher是怎么匹配的。
- public class PeopleContentProvider extends ContentProvider {
- private static final UriMatcher sUriMatcher;
- private static final int MATCH_FIRST = 1;
- private static final int MATCH_SECOND = 2;
- public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
- public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/frist");
- public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
- static {
- sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
- sUriMatcher.addURI(AUTHORITY, "second", MATCH_SECOND);
- }
- private DatabaseHelper mDbHelper;
- @Override
- public boolean onCreate() {
- mDbHelper = new DatabaseHelper(getContext());
- return false;
- }
- …………
- }
上面的代码是最重要的一句话:
sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
addUri的官方声明为:
public void addURI (String authority, String path, int code)
- authority:这个参数就是ContentProvider的authority参数,这个参数必须与AndroidManifest.xml中的对应provider的authorities值一样;
- path:就匹配在URI中authority后的那一坨,在这个例子中,我们构造了两个URI
(1)、content://com.harvic.provider.PeopleContentProvider/frist
(2)、content://com.harvic.provider.PeopleContentProvider/second
而path匹配的就是authority后面的/first或者/second - code:这个值就是在匹配path后,返回的对应的数字匹配值;
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
句话的意思是,如果匹配不成功,返回UriMatcher.NO_MATCH
我们要做一个应用:外部可以使用两个URI传来给我们,当传来content://com.harvic.provider.PeopleContentProvider/frist时,就操作first数据库;如果传来content://com.harvic.provider.PeopleContentProvider/second时,就操作second数据库
4、insert方法
下面先看看insert方法,主要功能为:当URI匹配content://com.harvic.provider.PeopleContentProvider/frist时,将数据插入first数据库
当URI匹配content://com.harvic.provider.PeopleContentProvider/second时,将数据插入second数据库
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- SQLiteDatabase db = mDbHelper.getWritableDatabase();
- switch (sUriMatcher.match(uri)){
- case MATCH_FIRST:{
- long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
- if(rowID > 0) {
- Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
- return retUri;
- }
- }
- break;
- case MATCH_SECOND:{
- long rowID = db.insert(DatabaseHelper.TABLE_SECOND_NAME, null, values);
- if(rowID > 0) {
- Uri retUri = ContentUris.withAppendedId(CONTENT_URI_SECOND, rowID);
- return retUri;
- }
- }
- break;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- return null;
- }
下面对上面这段代码进行讲解:
首先,利用UriMatcher.match(uri)来匹配到来的URI,如果这个URI与content://com.harvic.provider.PeopleContentProvider/frist匹配,就会返回1即MATCH_FIRST;
即:当与"/first"匹配时,就将数据键值对(values)插入到first表中:
long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
插入之后,会返回新插入记录的当前所在行号,然后将行号添加到URI的末尾,做为结果返回
Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
当匹配content://com.harvic.provider.PeopleContentProvider/second时,同理,不再赘述。
5、update()方法
在看了insert方法之后,update方法难度也不大,也是根据UriMatcher.match(uri)的返回值来判断当前与哪个URI匹配,根据匹配的URI来操作对应的数据库,代码如下:
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- SQLiteDatabase db = mDbHelper.getWritableDatabase();
- int count = 0;
- switch(sUriMatcher.match(uri)) {
- case MATCH_FIRST:
- count = db.update(DatabaseHelper.TABLE_FIRST_NAME, values, selection, selectionArgs);
- break;
- case MATCH_SECOND:
- count = db.update(DatabaseHelper.TABLE_SECOND_NAME, values, selection, selectionArgs);
- break;
- default:
- throw new IllegalArgumentException("Unknow URI : " + uri);
- }
- this.getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
在最后调用getContentResolver().notifyChange(uri, null);来通知当前的数据库有改变,让监听这个数据库的所有应用执行对应的操作,有关共享数据库的变量监听与响应的问题,我们会在最后一篇中讲述。这里就先不提,这里不加这一句也是没问题的。我这里只是一个引子,大家知道这个事就行了。
6、query() 方法
至于query()方法就不再细讲了,跟上面的一样,根据不同的URI来操作不同的查询操作而已,代码如下:
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
- SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
- switch (sUriMatcher.match(uri)) {
- case MATCH_FIRST:
- // 设置查询的表
- queryBuilder.setTables(DatabaseHelper.TABLE_FIRST_NAME);
- break;
- case MATCH_SECOND:
- queryBuilder.setTables(DatabaseHelper.TABLE_SECOND_NAME);
- break;
- default:
- throw new IllegalArgumentException("Unknow URI: " + uri);
- }
- SQLiteDatabase db = mDbHelper.getReadableDatabase();
- Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, null);
- return cursor;
- }
7、delete()方法
delete()方法如下:
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- SQLiteDatabase db = mDbHelper.getWritableDatabase();
- int count = 0;
- switch(sUriMatcher.match(uri)) {
- case MATCH_FIRST:
- count = db.delete(DatabaseHelper.TABLE_FIRST_NAME, selection, selectionArgs);
- break;
- case MATCH_SECOND:
- count = db.delete(DatabaseHelper.TABLE_SECOND_NAME, selection, selectionArgs);
- break;
- default:
- throw new IllegalArgumentException("Unknow URI :" + uri);
- }
- return count;
- }
8、getType()
这个函数,我们这里暂时用不到,直接返回NULL,下篇我们会专门来讲这个函数的作用与意义。
- public String getType(Uri uri) {
- return null;
- }
9、AndroidManifest.xml中声明provider
在AndroidManifest.xml中要声明我们创建的Provider:
- <provider
- android:authorities="com.harvic.provider.PeopleContentProvider"
- android:name=".PeopleContentProvider"
- android:exported="true"/>
二、第三方应用通过URI操作共享数据库
1、ContentResolver操作URI
在第三方应用中,我们要如何利用URI来执行共享数据数的操作呢,这是利用ContentResolver这个类来完成的。
获取ContentResolver实例的方法为:
ContentResolver cr = this.getContentResolver();
ContentResolver有下面几个数据库操作:查询、插入、更新、删除
- public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
- public final Uri insert (Uri url, ContentValues values)
- public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
- public final int delete (Uri url, String where, String[] selectionArgs)
第一个参数都是传入要指定的URI,然后再后面的几个参数指定数据库条件——where语句和对应的参数;下面我们就用户实例来看看这几个函数到底是怎么用的。
2、全局操作
新建一个工程,命名为“UseProvider”,界面长这个样子:
最上头有两个按钮,用来切换当前使用哪个URI来增、删、改、查操作;由于不同的URI会操作不同的数据表,所以我们使用不同的URI,会在不同的数据表中操作;
先列出来那两个要匹配的URI,以及全局当前要使用的URI(mCurrentURI ),mCurrentURI 默认是/first对应的URI,如果要切换,使用界面上最上头的那两个按钮来切换当前所使用的URI。
- public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
- public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/first");
- public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
- public static Uri mCurrentURI = CONTENT_URI_FIRST;
3、query()——查询操作
下面先来看看查询操作的过程:
- private void query() {
- Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
- Log.e("test ", "count=" + cursor.getCount());
- cursor.moveToFirst();
- while (!cursor.isAfterLast()) {
- String table = cursor.getString(cursor.getColumnIndex("table_name"));
- String name = cursor.getString(cursor.getColumnIndex("name"));
- String detail = cursor.getString(cursor.getColumnIndex("detail"));
- Log.e("test", "table_name:" + table);
- Log.e("test ", "name: " + name);
- Log.e("test ", "detail: " + detail);
- cursor.moveToNext();
- }
- cursor.close();
- }
其实只有一句话,就完成的查询操作:(由于没有加任何的限定语句,所以是查询出此数据表中的所有记录)
Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
然后将返回的数据库记录指针Cursor,逐个读出所有的记录;
4、insert()插入操作
public final Uri insert (Uri url, ContentValues values)
插入操作有点特殊,第二个函数要求传入要插入的ContentValues的键值对;其实也没什么难度,跟普通的数据库操作一样;
- private void insert() {
- ContentValues values = new ContentValues();
- values.put("name", "hello");
- values.put("detail", "my name is harvic");
- Uri uri = this.getContentResolver().insert(mCurrentURI, values);
- Log.e("test ", uri.toString());
- }
5、update()更新操作
public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
这个函数的意思就是,先用where语句找出要更新的记录,然后将values键值对更新到对应的记录中;
- uri:即要匹配的URI
- values:这是要更新的键值对
- where:SQL中对应的where语句
- selectionArgs:where语句中如果有可变参数,可以放在selectionArgs这个字符串数组中;这些与数据库中的用法一样,不再细讲。
- private void update() {
- ContentValues values = new ContentValues();
- values.put("detail", "my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!");
- int count = this.getContentResolver().update(mCurrentURI, values, "_id = 1", null);
- Log.e("test ", "count=" + count);
- query();
- }
在这里,我们将_id = 1的记录的detail字符更新,在后面多加了N个感叹号。
6、delete()删除操作
public final int delete (Uri url, String where, String[] selectionArgs)
删除操作的参数比较好理解,第二个参数是SQL中的WHERE语句的过滤条件,selectionArgs同样是Where语句中的可变参数;
- private void delete() {
- int count = this.getContentResolver().delete(mCurrentURI, "_id = 1", null);
- Log.e("test ", "count=" + count);
- query();
- }
删除_id = 1的记录;
三、结果
1、我们先运行ContentProvider对应的APP:ContentProviderBlog,然后再运行UseProvider;
2、然后先用content://com.harvic.provider.PeopleContentProvider/frist 来操作ContentProviderBlog的数据库:
3、点两个insert操作,看返回的URI,在每个URI后都添加上了当前新插入记录的行号
4、然后做下查询操作——query()
由于我们的URI是针对first记录的,所以在这里的table_name,可以看到是“first”,即我们操作的是first表,如果我们把URI改成second对应的URI,那操作的就会变成second表
5、更新操作——update()
执行Update()操作,会将_id = 1的记录的detail字段更新为“my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!”;其它记录的值不变,结果如下:
6、删除操作——delete()
同样,删除操作也会只删除_id = 1的记录,所以操作之后的query()结果如下:
总结:在这篇文章中,我们写了两个应用ContentProviderBlog和UseProvider,其中ContentProviderBlog派生自ContentProvider,提供第三方操作它数据库的接口;而UseProvider就是所谓第三方应用,在UseProvider中通过URI来操作ContentProviderBlog的数据库;
好了,到这里,整个文章就结束了,大家在看完这篇文章以后再回过头来看第一篇,应该对应用间数据库共享的整体流程已经有清晰的了解了。
源码来了,源码包含两部分内容:
1、《ContentProviderBlog》:这个是提供共享数据库接口的APP;
2、《UseProvider》:第三方通过URI来操作数据库的APP;
如果本文有帮到你,记得关注哦
源码下载地址:http://download.csdn.net/detail/harvic880925/8528507
请大家尊重原创者版权,转载请标明出处: http://blog.csdn.net/harvic880925/article/details/44591631 谢谢!
ContentProvider数据库共享之——实例讲解的更多相关文章
- 实例讲解Oracle数据库设置默认表空间问题
实例讲解Oracle数据库设置默认表空间问题 实例讲解Oracle数据库设置默认表空间问题,阅读实例讲解Oracle数据库设置默认表空间问题,DBA们经常会遇到一个这样令人头疼的问题:不知道谁在O ...
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- [转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)
linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习) https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 ...
- S3C2440上RTC时钟驱动开发实例讲解(转载)
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤.一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便.如有错误之处,谢请指正. 共享资源,欢迎转载:http:/ ...
- 详解:数据库名、实例名、ORACLE_SID、数据库域名、全局数据库名、服务名及手工脚本创建oracle数据库
数据库名.实例名.数据库域名.全局数据库名.服务名 , 这是几个令很多初学者容易混淆的概念.相信很多初学者都与我一样被标题上这些个概念搞得一头雾水.我们现在就来把它们弄个明白. 一.数据库名 什么是数 ...
- (转)SQLServer实例讲解
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- Oracle数据库名、实例名、数据库域名、全局数据库名、服务名之间的区别
数据库名.实例名.数据库域名.全局数据库名.服务名 这是几个令很多初学者容易混淆的概念.相信很多初学者都与我一样被标题上这些个概念搞得一头雾水.我们现在就来把它们弄个明白. 一.数据库名 什么是数据库 ...
- Android进阶(二十三)Android开发过程之实例讲解
Android开发过程之实例讲解 前言 回过头来审视之前做过的Android项目,发觉自己重新开发时忽然间不知所措了,间隔了太长时间没有开发导致自己的Android技能知识急剧下降.温故而知新. 废话 ...
- SQL Server 之 事务与隔离级别实例讲解
SQL Server 之 事务与隔离级别实例讲解 SQL Server 实现了6个隔离级别来防止并发情况下,类似企图并发的访问或修改同一数据时问题的发生.本文将带你体验全部6个隔离级别.正如你接下来将 ...
随机推荐
- java OutputStream的使用
package cn.kongxh.io3; import java.io.File ;import java.io.OutputStream ;import java.io.FileOutputSt ...
- day 33
目录 数据库是什么 为什么使用数据库 数据库的分类 关系型(把数据保存在硬盘里) 非关系型(把数据保存在内存里) mysql的架构 初识mysql 操作数据库 增 删 改 查 数据库是什么 数据库即存 ...
- python工程化最佳实践
1.pipenv 真实环境 vs virtualenv vs pipenv 2.自定义用户模型 继承BaseUserManager和AbstractBaseUser,在settings中指定AUTH_ ...
- 详解CentOS6.7部署Tomcat及主配置文件
Java程序实现部署及应用 POSIX :可移植操作系统,编程操作系统接口规范,实现跨平台编译运行. API:应用程序编程接口 ABI:应用程序二进制接口 描述了应用程序和操作系统之间,一个应用和它的 ...
- (十一)Kubernetes StatefulSet控制器
StatefulSet介绍 前面使用Deployment创建的Pod是无状态的,当挂载了volume之后,如果该Pod挂了,Replication Controller会再启动一个Pod来保证可用性, ...
- 从SQLAlchemy的“缓存”问题说起
https://www.jianshu.com/p/c0a8275cce99 0.4792017.11.22 00:07:04字数 1631阅读 6493 问题描述 最近在排查一个问题,为了方便说明, ...
- Unity基础功能:粒子特效(Shuriken)
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- Chrome出现“浏览器由所属组织管理”如何解决
之前碰到了这个问题,删除注册表解决了.当时没记下来,今天又碰到了.那就写下来以备之后再碰到吧 删除了注册表\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Ch ...
- Redis的入门
什么是NOSQL? NOSQL(Not Only SQL)不仅仅是数据库,是一种全新的理念,泛指非关系型的数据库. 为什么需要NOSQL? 随着互联网的高速崛起,网站的用户群的增加,访问量的上升,传统 ...
- python应用-n颗骰子的和出现的次数
from random import randint def roll_dice(n): total=0 for _ in range (n): num=randint(1,6) total+=num ...