背景

继Activty、Service之后,接下来认识一下它们的弟弟,ContentProvider。

这是他的学习路径思维导图

ContentProvider

定义

内容提供者

作用

  • 实现各个app应用、进程进行数据交互或者共享。(跨进程通信)
  • ContentProvider扮演的是中间者角色(搬运工),真正存储并且操作数据的数据源仍然为原来存储数据的方式。
  • ContentProvider一般是为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。

为什么选择ContentProvider

  • 对底层数据库抽象:ContnetProvider提供了对底层数据存储方式的抽象,在用了ContentProvider封装后,即使把数据库从SQLite换成MongoDB,也不会对上层数据使用层代码产生影响。
  • 封装统一数据类型:Android框架中的一些类需要ContentProvider类型数据,如果数据想使用在SyncAdapter,Loader,CursorAdapter等类上,就需要为数据做一层ContentProvider封装。
  • 用安全的方式封装:ContentProvider为应用间的数据交互提供了一个安全的环境。它准许你把自己的应用数据根据需求开放给其他应用进行增删改查,而不用担心直接开放数据库权限而带来的安全问题。

原理

ContentProvider的底层是采用Android的Binder机制。

下面是原理图

![具体使用

在使用之前先熟悉几个概念

统一资源标识符

定义

Uniform Resource Identifier,统一资源标识符。

作用

  • 唯一标识Content Provider
  • 外界进程可以通过Uri找到对应的ContentProvider
  • 可以对其中的数据进行操作

具体使用

Uri由两部分组成:authority和path

authority是对于不同的应用程序做区分的

path则是对同一应用程序中的不同表做区分的。

最标准的格式写法如下:

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

设置Uri

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

实例说明

读取系统联系人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.example.study.contentprovider;

import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.example.study.R;

import java.util.ArrayList;
import java.util.List;

public class ReadContactsActivity extends AppCompatActivity {

private ListView contacts_view;
ArrayAdapter<String> adapter;
List<String> contactsLists = new ArrayList<>();

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read_contacts);
contacts_view = (ListView) findViewById(R.id.contacts_view);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, contactsLists);

contacts_view.setAdapter(adapter);

//判断是否有READ_CONTACTS这个权限
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
} else {
readContacts();
}

}

private void readContacts() {
Cursor cursor = null;
try {
//查询联系人数据
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if(cursor != null){
while (cursor.moveToNext()){
//获取联系人姓名
String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//获取联系人手机号码
String displayNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

contactsLists.add(displayName + "\n" +displayNumber);
}
adapter.notifyDataSetChanged();
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(cursor != null){
cursor.close();
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
readContacts();
} else {
Toast.makeText(this, "You deined the P=permission", Toast.LENGTH_LONG).show();
}
break;
default:
}
}
}

MIME数据类型

作用

ContentProvider根据Uri返回MIME类型

组成

分类型+子类型

父类型为固定类型,用于区分单条/多条记录,子类型可自定义

形式1:单条记录:vnd.android.cursor.item/自定义
形式2:多条记录:vnd.android.cursor.dir/自定义

对于多条内容content://com.example.app.provider/table1这个内容的URI,它所对应的MIME类型就可以写成

vnd.android.cursor.dir/vnd.com.example.app.provider.table1

同理:对于单条内容的content://com.example.app.provider/table/1,他的MIME的类型可以写成

vnd.android.cursor.item/com.example.app.provider.table1

](https://img-blog.csdnimg.cn/20190520213431718.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5OTY2MjAz,size_16,color_FFFFFF,t_70)