ContentProvider是在应用程序间共享数据的一种接口机制,它还可以选择只对哪一部分数据进行共享,从而保证程序中的隐私数据不会有泄漏风险,ContentProvider主要负责存储和共享数据。其他应用程序通过ContentResolver类从该内容提供者中获取或存入数据。
一、访问系统提供的Provider数据
(1)ContentResolve类
- ContentResolver类中提供的一系列用于对数据进行增删改查操作的方法也酷似SQLiteDatabase的那些辅助性方法:
insert()方法用于添加数据(Uri对象,ContentValues对象)
update()方法用于更新数据(Uri对象,ContentValues对象,修改的约束条件,占位符的值)
delete()方法用于删除数据(Uri对象,删除的约束条件,占位符的值)
query()方法用于查询数据(Uri对象,查询的列名,查询的约束条件,占位符的值,排序方式) - 通过Context 中的getContentResolver()方法实例化一个ContentResolve对象
- 调用该对象的增删改查方法去操作ContentProvider中的数据。
(2)读取联系人信息
- 读取联系人信息
private void Contacts() {
//获取联系人的数据
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cursor != null) {
while (cursor.moveToFirst()) {
//获取联系人姓名
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
//获取联系人ID
int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
//获取联系人手机号数据
Cursor cursorPhone = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id,
null, null);
if (cursorPhone != null) {
while (cursorPhone.moveToFirst()) {
//获取联系人手机号
String phone = cursorPhone.getString(cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
cursorPhone.close();
}
}
cursor.close();
}
}
- 在配置文件中声明权限
- 注意:Android6.0以上的系统要求部分权限还要手动申请
int hasWriteContactsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 100);
}
return;
}
- 权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100){
for (int i = 0; i < grantResults.length; i ++){
if (grantResults[i] != PackageManager.PERMISSION_GRANTED){
//未获取权限
}
}
}
}
二、自定义创建Provider数据
(1)工具类:UriMatcher
- addURI()方法用来传入URI,它接收三个参数(权限,路径,匹配码)
- match()方法用来匹配URI,接受一个Uri对象,返回值是某个能够匹配这个Uri对象所对应的匹配码,利用这个匹配码,就可以判断出调用方期望访问的是哪张表中的数据。
(2)自定义ContentProvider
- 新建一个类去继承ContentProvider,重写ContentProvider的抽象方法。
public class MyContentProvider extends ContentProvider {
/**
* 创建ContentProvider后调用
*
* @return
*/
@Override
public boolean onCreate() {
return false;
}
/**
* 用于供外部应用从ContentProvider中查询数据
*
* @param uri
* @param projection
* @param selection
* @param selectionArgs
* @param sortOrder
* @return
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
/**
* 返回当前Uri所代表数据的MIME类型
*
* @param uri
* @return
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
/**
* 用于供外部应用向ContentProvider中增加数据
*
* @param uri
* @param values
* @return
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
/**
* 用于供外部应用从ContentProvider中删除数据
*
* @param uri
* @param selection
* @param selectionArgs
* @return
*/
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
/**
* 用于供外部应用更新ContentProvider中数据
*
* @param uri
* @param values
* @param selection
* @param selectionArgs
* @return
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
- 在配置文件中进行注册,并注明属性
(3)示例具体实现
public class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建表student
db.execSQL("create table if not exists animal(" +
"_id integer primary key autoincrement, " +
"name text not null , " +
"age integer not null , " +
"sex text not null)");
db.execSQL("create table if not exists person(" +
"_id integer primary key autoincrement, " +
"name text not null , " +
"age integer not null , " +
"sex text not null)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL("create table if not exists person(" +
"_id integer primary key autoincrement, " +
"name text not null , " +
"age integer not null , " +
"sex text not null)");
break;
}
}
}
public class MyContentProvider extends ContentProvider {
public DBOpenHelper dbOpenHelper;
public static UriMatcher uriMatcher;
public static final int ANIMAL_DIR = 1001;
public static final int ANIMAL_ITEM = 1002;
public static final int PERSON_DIR = 1003;
public static final int PERSON_ITEM = 1004;
public static final String AUTHORITIES = "com.example.dbsqlite.mycontentprovider";
//对UriMatcher进行了初始化
//id用以区分表中不同的数据记录,如果没有id就返回全部。用到了转义符。#代表任意数字,*代表任意字母。
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITIES, "animal", ANIMAL_DIR);
uriMatcher.addURI(AUTHORITIES, "animal/#", ANIMAL_ITEM);
uriMatcher.addURI(AUTHORITIES, "person", PERSON_DIR);
uriMatcher.addURI(AUTHORITIES, "person/#", PERSON_ITEM);
}
/**
* 该方法在ContentProvider被其它应用第一次访问它时才会被创建
* 返回true表示内容提供器初始化成功
*
* @return
*/
@Override
public boolean onCreate() {
dbOpenHelper = new DBOpenHelper(getContext(), "UserInfo.db", null, 2);
return true;
}
/**
* 用于供外部应用从ContentProvider中查询数据
*
* @param uri
* @param projection
* @param selection
* @param selectionArgs
* @param sortOrder
* @return
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
String id;
Cursor cursor = null;
//获取到SQLiteDatabase的实例
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
//判断用户查询哪张表
switch (uriMatcher.match(uri)) {
case ANIMAL_DIR:
cursor = db.query("animal", projection, selection, selectionArgs, null, null, sortOrder);
break;
case ANIMAL_ITEM:
//调用Uri对象的getPathSegments()方法
//它会将内容URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,
//那这个列表的第0个位置存放的就是路径,第1个位置存放的就是id
id = uri.getPathSegments().get(1);
cursor = db.query("animal", projection, "id=?", new String[]{id}, null, null, sortOrder);
break;
case PERSON_DIR:
cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
break;
case PERSON_ITEM:
id = uri.getPathSegments().get(1);
cursor = db.query("person", projection, "id=?", new String[]{id}, null, null, sortOrder);
break;
}
return cursor;
}
/**
* 返回当前Uri所代表数据的MIME类型
* 内容URI所对应的MIME字符串主要由三部分组分,
* Android对这三个部分做了以下格式规定:必须以vnd开头;
* 如果内容URI以路径结尾,则后接android.cursor.dir/,
* 如果内容URI以id结尾,则后接android.cursor.item/;
* 最后接上vnd.< authority>.< path>。
*
* @param uri
* @return
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
//与已经注册的Uri进行匹配
switch (uriMatcher.match(uri)) {
case ANIMAL_DIR:
return "vnd.android.cursor.dir/vnd.com.example.dbsqlite.mycontentprovider.animal";
case ANIMAL_ITEM:
return "vnd.android.cursor.item/vnd.com.example.dbsqlite.mycontentprovider.animal";
case PERSON_DIR:
return "vnd.android.cursor.dir/vnd.com.example.dbsqlite.mycontentprovider.person";
case PERSON_ITEM:
return "vnd.android.cursor.item/vnd.com.example.dbsqlite.mycontentprovider.person";
}
return null;
}
/**
* 用于供外部应用向ContentProvider中增加数据
*
* @param uri
* @param values
* @return
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Uri uri_return = null;
long id;
//判断向哪张表里添加数据
switch (uriMatcher.match(uri)) {
case ANIMAL_DIR:
case ANIMAL_ITEM:
id = db.insert("animal", null, values);
uri_return = Uri.parse("content://" + AUTHORITIES + "/animal/" + id);
break;
case PERSON_DIR:
case PERSON_ITEM:
id = db.insert("person", null, values);
uri_return = Uri.parse("content://" + AUTHORITIES + "/person/" + id);
break;
}
return uri_return;
}
/**
* 用于供外部应用从ContentProvider中删除数据
*
* @param uri
* @param selection
* @param selectionArgs
* @return
*/
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
String id;
int row = 0;
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
switch (uriMatcher.match(uri)) {
case ANIMAL_DIR:
row = db.delete("animal", selection, selectionArgs);
break;
case ANIMAL_ITEM:
id = uri.getPathSegments().get(1);
row = db.delete("animal", "id=?", new String[]{id});
break;
case PERSON_DIR:
row = db.delete("person", selection, selectionArgs);
break;
case PERSON_ITEM:
id = uri.getPathSegments().get(1);
row = db.delete("person", "id=?", new String[]{id});
break;
}
return row;
}
/**
* 用于供外部应用更新ContentProvider中数据
*
* @param uri
* @param values
* @param selection
* @param selectionArgs
* @return
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
String id;
int row = 0;
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
switch (uriMatcher.match(uri)) {
case ANIMAL_DIR:
row = db.update("animal", values, selection, selectionArgs);
break;
case ANIMAL_ITEM:
id = uri.getPathSegments().get(1);
row = db.update("animal", values, "id=?", new String[]{id});
break;
case PERSON_DIR:
row = db.update("person", values, selection, selectionArgs);
break;
case PERSON_ITEM:
id = uri.getPathSegments().get(1);
row = db.update("person", values, "id=?", new String[]{id});
break;
}
return row;
}
}
三、使用ContentResolver调用ContentProvider操作数据库数据
(1)ContentResolver基础方法
ContentResolver resolver = getContentResolver();
//该方法用于往ContentProvider添加数据。
public Uri insert(Uri uri, ContentValues values);
//该方法用于从ContentProvider删除数据。
public int delete(Uri uri, String selection, String[] selectionArgs);
//该方法用于从ContentProvider中获取数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
//该方法用于更新ContentProvider中的数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
(2)数据的增删改查操作
private ContentValues values;
private ContentResolver resolver;
private Uri uri;
private Uri uri_new;
private Uri uri_return;
public void init() {
values = new ContentValues();
resolver = getContentResolver();
uri = Uri.parse("com.example.dbsqlite.mycontentprovider/animal");
}
public void insert() {
values.put("name", "cat");
values.put("age", 2);
values.put("sex", "male");
uri_return = resolver.insert(uri, values);
values.clear();
values.put("name", "tiger");
values.put("age", 2);
values.put("sex", "male");
uri_return = resolver.insert(uri, values);
String id = uri_return.getPathSegments().get(1);
uri_new = Uri.parse("content://com.example.dbsqlite.mycontentprovider/animal" + id);
values.clear();
values.put("name", "lion");
values.put("age", 4);
values.put("sex", "female");
uri_return = resolver.insert(uri, values);
values.clear();
}
public void delete() {
resolver.delete(uri_new, null, null);
}
public void update() {
values.put("age", 5);
resolver.update(uri, values, "age=?", new String[]{"4"});
}
public void query() {
Cursor cursor = resolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
}
cursor.close();
}
}