您的位置:首页 > 其它

内容提供器---Content Provider

2015-12-16 22:19 323 查看

Content Provider

内容提供者主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。目前,使用内容提供者是Android实现跨程序共享数据的标准方式。不同于文件存储和SharedPreferences存储中的两种全局可读写操作模式,内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会被泄露的风险。

内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序提供外部访问接口。

访问其他程序中的数据

对于每一个应用程序来说,如果想要访问内容提供器中共享的数据,就一定要借助ContentResolve类,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver中提供了一系列的方法用于对数据进行增删改查操作。insert()、update()、delete()、query()等方法。


URI 内容URI给内容提供器中的数据建立了唯一标识符,主要由两部分组成,权限(authority)和路径(path)。权限是用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。

URL最标准的格式写法如下:

content://com.example.app.provider/table1

解析成Uri对象才可以作为参数传入,解析的方法也相当简单,代码如下:

Uri uri =Uri.parse(“content://com.example.app.provider/table1”);

增、删、改、查

Cursor cursor =getContentResolver().query(
uri,  //Uri 对象
projection, //要查询的列名
selection,  //约束条件
selectionArgs, //约束条件及其值
sortOrder  //指定查询结果的排序方式
);


ContentValues values=new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);


ContentValues values=new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[]{"text",1});


删除

getContentResolver().delete(uri,"column2 = ?",new String[]{"1"});


创建自己的内容提供器

提供给外部访问接口的应用程序都是如何实现增删改查,并且保证共享数据的安全的呢?下面我们继续探究。

继承ContentProvider类

public class MyProvider extends ContentProvider{
public boolean onCreate(){
return false;
}

public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
return null;
}

public Uri insert(Uri uri,ContentValues values){
return null;
}

public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
return 0;
}

public int delete(Uri uri,String selection,String[] selectionArgs){
return 0;
}

public String getType(){
return null;
}
}

onCreate()
初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。

query()
从内容提供器中查询数据。使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和seletionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。

insert()
向内容提供器中添加一条数据。使用uri参数来确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。

update()
更新内容提供器中已有的数据,返回的结果是受影响的行数将作为返回值返回。

delete()
从内容提供器中删除数据。被删除的行数将作为返回值返回。
getType()
根据传入的内容URI来返回相应的MIME类型。


匹配

使用通配符的方式来分别匹配这两种格式的内容URI,规则如下。
1、*:表示匹配任意长度的任意字符
2、#:表示匹配任意长度的数字
所以,一个能够匹配任意表的内容URI格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:
content://com.example.app.provider/table1/#

我们借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。UriMatcher中提供一个addURI()方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。这样,当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。

public class MyProvider extends ContentProvider{
public static final int TABLE_DIR=0;
public static final int TABLE_ITEM=1;
public static final int TABLE2_DIR =2;
public static final int TABLE2_ITEM=3;
static{
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider","table1/#",TABLE_ITEM);
uriMatcher.addURI("com.example.app.provider","table2",TABLE2_ITEM);
uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
}

public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
switch(uriMatcher.match(uri)){
case TABLE_DIR:
//查询table1表中的所有数据
break;
case TABLE_ITEM;
//查询table1表中的单条数据
break;
case TABLE2_DIR;
//查询table2 表中的所有数据
break;
case TABLE2_ITEM:
//查询table2表中的单条数据
break;
default:
break;
}
}
}

getType()方法。它是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。一个内容URI所对应的MIME字符串主要由三个部分组成,Android 对这三个部分做了如下格式规定。
1、必须以vnd开头。
2、如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/。
3、最后接vnd.<authority>.<path>
如:对于content://com.example.app.provider/table1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1


getType()逻辑:

public String getType(Uri uri){
switch(uriMatcher.match(uri)){
case TABLE_DIR:
return "vnd.android.cursor.dir/vnd/com.example.app.provider/table1";
case TABLE_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
default:
break;
}
return null;
}


注:

String bookId = uri.getPathSegments().get(1);
updatedRows = db.update("Book",values,"id = ?",new String[]{bookId});
当访问单条数据的时候,这里调用了Uri对象的getPathSegments()方法,它会将内容URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,那这个列表的第0个位置存放的就是路径,第1个位置存放的就是id了。得到了id之后,再通过selection和selectionArgs参数进行约束,就实现了查询单条数据的功能。


内容提供器注册

全类名+权限

<provider
android:name="com.example.databasetest.DatabaseProvider"
android:authorities="com.example.databasetest.provider">
</provider>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: