如果想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承ContentProvider的方式来创建一个自己的内容提供器。ContentProvider类中有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。新建MyProvider继承自ContentProvider,代码如下所示:
package com.example.administrator.contactstest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class MyProvider 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;
}
}
1.onCreate():初始化内容提供器的时候调用。通常会在这里完成对数据的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败。
2.query():从内容提供器中查询数据。使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。
3.insert():向内容提供器中添加一条数据。使用uri参数来确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URL。
4.update():更新内容提供器中已有的数据。使用uri参数来确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。
5.delete():从内容提供器中删除数据。使用uri参数来确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪行,被删除的行将作为返回值返回。
6.getType():
根据传入的内容URI来返回相应的MIME类型。
匹配任意表的内容URI格式:
content://com.example.app.provider/*
匹配table表中的任意一行数据的内容URI格式:
content://com.example.app.provider/table/#
我们需要使用UriMatcher类来实现匹配内容URI的功能,UriMatcher类中提供了一个addURI()方法,这个方法接收3个参数,可以分别把authority、path和自定义int类型标识符传进去。这样,当调用UriMatcher的match()方法时,就可以将一个uri对象传入,返回值是某个可以匹配这个uri对象所对应的int类型标识符(也就是addURI()方法中的第三个参数),利用该int类型标识符,我们就可以判断出调用方期望访问的是哪张表中的数据了。
修改MainActivity.java代码:
package com.example.administrator.contactstest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
public class MyProvider extends ContentProvider {
public static final int TABLE1_DIR = 0;//table1表中的所有数据
public static final int TABLE1_ITEM = 1;//table1表中的单条数据
public static final int TABLE2_DIR = 2;//table2表中的所有数据
public static final int TABLE2_ITEM = 3;//table2表中的单条数据
public static UriMatcher uriMatcher;//声明uri匹配类对象
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);//实例化uri匹配类对象
//向UriMatcher中添加内容URI
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider", "table2", TABLE2_DIR);
uriMatcher.addURI("com.example.app.provider", "table2/#", TABLE2_ITEM);
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
//查询table1表中的所有数据
break;
case TABLE1_ITEM:
//查询table1表中的单条数据
break;
case TABLE2_DIR:
//查询table2表中的所有数据
break;
case TABLE2_ITEM:
//查询table2表中的单条数据
break;
default:
break;
}
return null;
}
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;
}
}
这里再讲一下getType()方法,它是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。一个内容URI所对应的MIME字符串主要由3部分组成,Android对这3部分做了如下格式规定:
1.必须以vnd开头
2.如果内容URI以路径结尾,则在vnd后面加上android.cursor.dir/,如果以id结尾,则在vnd后面加上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
对于content://com.example.app.provider/table1/1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.item/vnd.com.example.app.provider.table1
ManiActivity.java代码:
package com.example.administrator.contactstest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
public class MyProvider extends ContentProvider {
public static final int TABLE1_DIR = 0;//table1表中的所有数据
public static final int TABLE1_ITEM = 1;//table1表中的单条数据
public static final int TABLE2_DIR = 2;//table2表中的所有数据
public static final int TABLE2_ITEM = 3;//table2表中的单条数据
public static UriMatcher uriMatcher;//声明uri匹配类对象
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);//实例化uri匹配类对象
//向UriMatcher中添加内容URI
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider", "table2", TABLE2_DIR);
uriMatcher.addURI("com.example.app.provider", "table2/#", TABLE2_ITEM);
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
//查询table1表中的所有数据
break;
case TABLE1_ITEM:
//查询table1表中的单条数据
break;
case TABLE2_DIR:
//查询table2表中的所有数据
break;
case TABLE2_ITEM:
//查询table2表中的单条数据
break;
default:
break;
}
return null;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
case TABLE1_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;
}
@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;
}
}
到这里,一个完整的内容提供器就创建成功了,现在任何一个应用程序都可以使用ContentResolver来访问我们程序中的数据。那么前面所提到的,如何才能保证隐私数据不会泄露出去呢?其实多亏了内容提供器的良好机制,这个问题在不知不觉中被解决了。因为所有的CRUD操作都需要匹配到相应的内容URI,而这些内容URI都是需要我们自主的往UriMatcher中添加的,我们当然不会主动将一些隐私数据的URI添加到UriMatcher中,所以隐私的数据外界是无法访问到的。