文章目录
![ContentProvider](https://i-blog.csdnimg.cn/blog_migrate/7c5332c0ca9ef74ac8dfe8d20b71a154.png)
1. 定义
- Android四大组件之一
- 用于在不同应用程序之间实现数据共享的功能
- 内容提供其可以选择只对哪一部分数据进行共享,保证隐私数据的安全性
2. 使用
1. 使用 ContentResolver访问其他应用中数据
ContentResolver的方法 | 说明 | 补充 |
---|---|---|
Cursor query(Uri uri,String[] projection, String selection,String[] selectionArgs, String sortOrder) | 查询 | uri:内容URI,给数据建立唯一标识符 projection:指定查询的列名 selection:指定的约束条件 selectionArgs:约束条件中具体的值 sortOrder:排序方式 |
Uri insert(Uri url, ContentValues values) | 新增 | uri:内容URI,给数据建立唯一标识符 values:插入数据的数据集 |
int update(Uri uri, ContentValues values, String where, String[] selectionArgs) | 修改 | uri:内容URI,给数据建立唯一标识符 values:要修改数据的数据集 where:指定的约束条件 selectionArgs:约束条件中具体的值 |
int delete(Uri url, @Nullable String where, String[] selectionArgs) | 删除 | uri:内容URI,给数据建立唯一标识符 where:指定的约束条件 selectionArgs:约束条件中具体的值 |
Uri: 主要有两部分组成,authority和path
- authority用于对不同的应用程序做区分,一般为了避免冲突,都会采用程序包名的方式进行命名
- path用于对同一应用程序不同表做区分,通常添加到authority后面
标准格式写法
content://com.xxx.app.provider/table
表示调用方期望的是访问这个应用程序的table表的数据content://com.xxx.app.provider/table/1
表示调用方期望的是访问这个应用程序的table表中id为1的数据路径结尾表示期望访问该表中所有数据
id结尾表示期望访问该表中对应id的数据
读取系统联系人
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); msgTv.setText(msgTv.getText().toString() + "\n" + "readContacts: " + name + ":" + number); } }
通过Context的getContentResolver方法获取该实例
通过insert()update() delete() query()实现CRUD
2. 创建ContentProvider提供给其他应用程序访问本应用数据
2.1 实现说明
创建MyContentProvider继承ContentProvider,重写6个方法
需实现的方法 | 说明 | 补充 |
---|---|---|
boolean onCreate() | 初始化内容提供器 通常在这里完成数据库的创建、升级等操作 | 返回值表示创建成功与否 它的执行早于Application的OnCreate; |
String getType(Uri uri) | 根据传入的内容URI来返回相应的MIME类型 | 必须实现 IMEI含义:简单来说 描述了由uri参数计算出的数据类型 |
Uri insert(Uri uri, ContentValues values) | 增,返回一个用于表示这条新纪录的URI | 参数,同ContentResolver中参数意义 |
int delete(Uri uri, String selection, String[] selectionArgs) | 删,返回值为被删除的行数 | 参数,同ContentResolver中参数意义 |
int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) | 改,返回值为被更改的行 | 参数,同ContentResolver中参数意义 |
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) | 查,返回值为存储查询结果的cursor | 参数,同ContentResolver中参数意义 |
MIME 主要由三部分组成
必须以 vnd 开头
content uri 以路径结尾,则后接 android.cursor.dir/
content uri 以id结尾,则后接 android.cursor.item/最后接上 vnd.authority(实际值).path(实际值)
content://com.xxx.app.provider/table
对应MIME
vnd.android.cursor.dir/com.xxx.app.provider.tablecontent://com.xxx.app.provider/table/1
对应MIME
vnd.android.cursor.item/com.xxx.app.provider.table
2.2 自定义ContentProvider
package com.sj.a_4_contentprovider_b;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import com.sj.a_4_contentprovider_b.db.DBTables;
import com.sj.a_4_contentprovider_b.db.DBUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyContentProvider extends ContentProvider {
public static final int DATA_DIR = 0;
public static final int DATA_ITEM = 1;
private static UriMatcher uriMatcher;
private static String AUTHORITY = "com.sj.a_4_contentprovider_b.provider";
private static String PATH = "data";
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, PATH, DATA_DIR);
uriMatcher.addURI(AUTHORITY, PATH + "/#", DATA_ITEM);
}
@Override
public boolean onCreate() {
ContentValues contentValues = new ContentValues();
contentValues.put("d1", "D1" + System.currentTimeMillis() + "");
contentValues.put("d2", "D1" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
DBUtils.insert(DBTables.DATA, null, contentValues);
contentValues.clear();
contentValues.put("d1", "D2" + System.currentTimeMillis() + "");
contentValues.put("d2", "D2" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
DBUtils.insert(DBTables.DATA, null, contentValues);
contentValues.clear();
contentValues.put("d1", "D3" + System.currentTimeMillis() + "");
contentValues.put("d2", "D3" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
DBUtils.insert(DBTables.DATA, null, contentValues);
contentValues.clear();
contentValues.put("d1", "D4" + System.currentTimeMillis() + "");
contentValues.put("d2", "D4" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
DBUtils.insert(DBTables.DATA, null, contentValues);
return true;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case DATA_DIR:
return "vnd.android.cursor.dir/" + AUTHORITY + "." + PATH;
case DATA_ITEM:
return "vnd.android.cursor.item/" + AUTHORITY + "." + PATH;
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long id = DBUtils.insert(DBTables.DATA, null, values);
return Uri.parse("content://" + AUTHORITY + "/" + PATH + "/" + id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (uriMatcher.match(uri)) {
case DATA_DIR:
return DBUtils.delete(PATH, selection, selectionArgs);
case DATA_ITEM:
String dataId = uri.getPathSegments().get(1);
return DBUtils.delete(PATH, "id=?", new String[]{dataId});
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
switch (uriMatcher.match(uri)) {
case DATA_DIR:
return DBUtils.update(PATH, values, selection, selectionArgs);
case DATA_ITEM:
String dataId = uri.getPathSegments().get(1);
return DBUtils.update(PATH, values, "id=?", new String[]{dataId});
}
return 0;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case DATA_DIR:
return DBUtils.query(PATH, projection, selection, selectionArgs, null, null, sortOrder);
case DATA_ITEM:
String dataId = uri.getPathSegments().get(1);
return DBUtils.query(PATH, projection, "id=?", new String[]{dataId}, null, null, sortOrder);
}
return null;
}
}
2.3 使用
注意uri要完全正确匹配,调用参考 a_4_contentprovider_a
3. 问题
- 只有当存在ContentResolver尝试访问本程序中的数据时,才会被初始化 与实际编写时onCreate的触发时机有出入,存在问题待解决
- Failed to find provider info for com.sj.a_4_contentprovider_b.provider
注意清单文件中authorities要写全,不要遗漏 .provider - 示意demo未做权限适配,需要手动给予通讯录权限