Android内容提供者

1.什么是ContentProvider

首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少。 ContentProvider为不同的软件之间数据共享,提供统一的接口。也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件、数据库内存储的信息。当然,自己开发的应用需要给其他应用共享信息的需求可能比较少见,但是在Android系统中,很多系统自带应用,比如联系人信息,图片库,音频库等应用,为了对其他应用暴露数据,所以就使用了ContentProvider机制。所以,我们还是要学习ContentProvider的基本使用,在遇到获取联系人信息,图片库,音频库等需求的时候,才能更好的实现功能

2.如何定义一个ContentProvider

Android系统为了让我们更好的对外暴露数据,提供了统一的接口,所以定义了抽象类ContentProvider,因此,如果我们想对外提供数据,我们需要继承ContentProvider,并且实现下面的这几个方法:

onCreate() 当我们的provider初始化时被调用,我们应该在这个方法里面完成部分初始化操作 query() 查询方法,用于给调用者返回数据 insert() 插入操作,用于让外部应用插入数据到内容提供者中 update() 更新操作,用于更新内容提供者的数据 delete() 用于删除数据 getType 返回内容提供者的MIME Type

上面这些方法,当我们继承自ContentProvider的时候,eclipse会自动的给我们添加,但是这并不代表我们每个方法都需要自定义实现。如果我们只希望给其他应用提供数据,而不允许其他应用修改我们的数据,那么我们只需要实现onCreate(),getType()和query()这三个方法就可以了,其他的三个方法我们可以根据业务需求,实现或者是不实现。

因为一般使用ContentProvider向外部暴露数据库的信息,因此,本篇将以使用ContentProvider向其他应用暴露数据库信息为例,讲解ContentProvider的基本使用。

Android中SQLite数据库的创建和使用,本篇不再介绍,不清楚的请看这篇文章 SQLite数据库的简单实用

假设读者已经学会了SQLite数据库的使用,并且已经建立好了数据库,下面我们开始写我们的ContentProvider。 因为注释解析的比较详细,所以就不过多解释了

/**

* Copyright  :版权所有2016

* Author    :坏叔叔

* Date      : 2016/8/21 16:51

*/

public classStudentProviderextendsContentProvider {

//数据库操作类,用于获取SQLiteDatabase

privateMyDbOpenHelperdbHelper;

private static final intSTUDENT=1;

private static final intSTUDENTS=2;

// UriMatcher类是一个很重要的类,因为我们需要根据传入的uri,来判断执行相对应的操作

private static finalUriMatcherMATCHER=newUriMatcher(UriMatcher.NO_MATCH);

//静态代码块用于初始化MATCHER需要匹配的uri

static{

// MATCHER.addURI(主机名(用于唯一标示一个ContentProvider,这个需要和清单文件中的authorities属性相同),路径(可以用来表示我们要操作的数据,路径的构建应根据业务而定),返回值(用于匹配uri的时候,作为匹配的返回值));

MATCHER.addURI("com.example.mydbdemo.StudentProvider","student",STUDENTS);

MATCHER.addURI("com.example.mydbdemo.StudentProvider","student/#",STUDENT);

}

@Override

public booleanonCreate() {

dbHelper=newMyDbOpenHelper(getContext());

return false;

}

//查询

//如果uri为content://com.example.mydbdemo.StudentProvider/student

//则代表查询所有的student表内的数据

//如果uri为content://com.example.mydbdemo.StudentProvider/student/6

//则代表查询student表内id=6的数据

@Override

publicCursorquery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

SQLiteDatabase db =dbHelper.getReadableDatabase();

//判断传入的uri到底匹配哪一个,从而实现不同的业务需求

switch(MATCHER.match(uri)) {

//查询全部的学生信息

caseSTUDENTS:

//db.query(表明,要查询的列(是一个String数组), where条件, where条件中的参数, groupBy, having, sortOrder);

returndb.query("student", projection, selection, selectionArgs,null,null, sortOrder);

//查询某一个id对应的学生的信息

caseSTUDENT:

//取出我们要查询的数据的id

longid = ContentUris.parseId(uri);

String where ="id="+ id;

//将selection查询信息拼接到我们的where条件中

if(selection !=null&& !"".equals(selection)) {

where = selection +" and "+ where;

}

returndb.query("student", projection, where, selectionArgs,null,null, sortOrder);

//如uri不匹配,抛出不合法参数的异常

default:

throw newIllegalArgumentException("Unkwon Uri:"+ uri.toString());

}

}

//获取MIME TYPE

@Override

publicStringgetType(Uri uri) {

switch(MATCHER.match(uri)) {

caseSTUDENT:

return"vnd.android.cursor.item/student";

caseSTUDENTS:

return"vnd.android.cursor.dir/student";

default:

throw newIllegalArgumentException("Unkwon Uri:"+ uri.toString());

}

}

//插入数据

@Override

publicUriinsert(Uri uri, ContentValues values) {

SQLiteDatabase db =dbHelper.getWritableDatabase();

switch(MATCHER.match(uri)) {

caseSTUDENTS:

longid = db.insert("student","name", values);

returnContentUris.withAppendedId(uri, id);

default:

throw newIllegalArgumentException("Uri不匹配");

}

}

//删除数据

@Override

public intdelete(Uri uri, String selection, String[] selectionArgs) {

SQLiteDatabase db =dbHelper.getWritableDatabase();

intcount =0;

switch(MATCHER.match(uri)) {

caseSTUDENTS:

count = db.delete("student", selection, selectionArgs);

returncount;

caseSTUDENT:

longid = ContentUris.parseId(uri);

String where ="id="+ id;

if(selection !=null&& !"".equals(selection)) {

where = selection +" and "+ where;

}

count = db.delete("student", where, selectionArgs);

returncount;

default:

throw newIllegalArgumentException("Unkwon Uri:"+ uri.toString());

}

}

//更新数据

@Override

public intupdate(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

SQLiteDatabase db =dbHelper.getWritableDatabase();

intcount =0;

switch(MATCHER.match(uri)) {

caseSTUDENTS:

count = db.update("student", values, selection, selectionArgs);

returncount;

caseSTUDENT:

longid = ContentUris.parseId(uri);

String where ="id="+ id;

if(selection !=null&& !"".equals(selection)) {

where = selection +" and "+ where;

}

count = db.update("student", values, where, selectionArgs);

returncount;

default:

throw newIllegalArgumentException("Unkwon Uri:"+ uri.toString());

}

}

}

我们在定义好我们的ContentProvider之后,因为ContentProvider数据四大组件之一,因此我们还需要在AndroidManifest清单文件中进行注册才能使用,下面是注册信息

android:name="com.example.mydbdemo.StudentProvider"

android:exported="true"

android:authorities="com.example.mydbdemo.StudentProvider" >

注意,provider的声明和activity一样,都是在application节点进行声明的。

至此,我们就完成了我们自己的ContentProvider的生命,其他的应用现在就可以使用我们往外部暴露的数据信息了。

3.外部应用如何使用我们的ContentProvider

我们已经定义好了我们自己的ContentProvider,那么外部应用如何调用呢? 下面,我将新建一个测试单元工程,完成对ContentProvider的各个方法的测试

添加方法测试

//使用ContentProvider添加数据的测试

public void testadd() throws Throwable {

//获取ContentResolver对象,完成对ContentProvider的调用

ContentResolver contentResolver = this.getContext().getContentResolver();

//构建我们的uir,这个uri

Uri insertUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");

ContentValues values = new ContentValues();

values.put("name", "zhaokaikai");

values.put("age", 91);

values.put("school", "bbbb");

//返回值为我们刚插入进入的数据的uri地址

Uri uri = contentResolver.insert(insertUri, values);

Log.i(TAG, uri.toString());

}

删除测试方法

//使用ContentProvider删除数据的测试

public void testDelete() throws Throwable {

ContentResolver contentResolver = this.getContext().getContentResolver();

//删除id为6的学生信息

Uri deleteUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");

contentResolver.delete(deleteUri, null, null);

}

修改测试方法

//使用ContentProvider更新数据的测试

public void testUpdate() throws Throwable {

ContentResolver contentResolver = this.getContext().getContentResolver();

//更新id = 6 的学生信息

Uri updateUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");

ContentValues values = new ContentValues();

values.put("name", "testUp");

values.put("age", "101");

values.put("school", "ccccc");

contentResolver.update(updateUri, values, null, null);

}

查询数据测试

//使用ContentProvider查询数据的测试

public void testFind() throws Throwable {

ContentResolver contentResolver = this.getContext().getContentResolver();

//这个uri用于查询所有的数据,若查询某个id的数据,则构建下面的uri

//Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/要查询的id");

Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");

Cursor cursor = contentResolver.query(selectUri, null, null, null, "id desc");

while (cursor.moveToNext()) {

int id = cursor.getInt(cursor.getColumnIndex("id"));

String name = cursor.getString(cursor.getColumnIndex("name"));

int age = cursor.getInt(cursor.getColumnIndex("age"));

String school = cursor.getString(cursor.getColumnIndex("school"));

Log.i(TAG, "id=" + id + ",name=" + name + ",age=" + age +",school="+school);

}

}

上面的方法都经过了单元测试。

好了,至此,我们就使用ContentProvider实现了在第三方应用中对我们应用的数据库进行增删改查等操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容