ContentProvider主要用于不同应用程序之间共享数据,比如联系人、短信、媒体库等都实现了跨应用数据共享功能。

ContentProvider在提供数据共享的同时还能保证被访问数据的安全性。

代码演示“读取联系人”

创建一个项目ContentProviderSample

新建 Activity,名为 ContactsActivity

配置 AndroidManifest.xml,添加读取联系人权限

编辑布局文件 activity_main.xml

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:gravity="center_horizontal"

android:padding="30dp">

android:id="@+id/contactsBtn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="read contacts" />

增加了一个按钮,用于启动ContactsActivity。

编辑 MainActivity

Java 代码

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Button contactsBtn = findViewById(R.id.contactsBtn);

contactsBtn.setOnClickListener(view -> {

Intent intent = new Intent(this, ContactsActivity.class);

startActivity(intent);

});

}

Kotlin 代码

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val contactsBtn: Button = findViewById(R.id.contactsBtn)

contactsBtn.setOnClickListener{

val intent = Intent(this, ContactsActivity::class.java)

startActivity(intent)

}

}

给按钮增加监听,点击跳转ContactsActivity。

编辑布局文件 activity_contacts.xml

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:gravity="center_horizontal"

android:padding="30dp">

android:id="@+id/contactsTv"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textSize="15sp"

android:hint="contacts" />

TextView用于呈现读取到的联系人数据,这里简化处理了。

编辑 ContactsActivity

Java 代码

public class ContactsActivity extends AppCompatActivity {

private TextView tv;

private final List contractsList = new LinkedList<>();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_contacts);

tv = findViewById(R.id.contactsTv);

mayReadTheContacts();

}

private void mayReadTheContacts() {

if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(

this,

Manifest.permission.READ_CONTACTS

)

) {

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 101);

} else {

readTheContacts();

}

}

/**

* 读取联系人数据

*/

private void readTheContacts() {

contractsList.clear();

Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,

null, null, null, null);

// 遍历每一条联系人的数据

while (cursor.moveToNext()) {

// 读取联系人数据在系统中的id,以及联系人名称

String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));

String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

// 读取联系人的电话号码

StringBuilder numbers = new StringBuilder();

Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null);

while (phones.moveToNext()) {

String num = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

numbers.append(num).append(" ");

}

phones.close();

// 读取联系人的邮箱

StringBuilder address = new StringBuilder();

Cursor mails = getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,

null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + id, null, null);

while (mails.moveToNext()) {

String mail = mails.getString(mails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));

address.append(mail).append(" ");

}

mails.close();

contractsList.add(String.format("[%s] %s\n%s\n%s", id, name, numbers.toString(), address.toString()));

}

cursor.close();

// 界面显示联系人的数据

updateUI();

}

private void updateUI() {

tv.setText("");

for (String s : contractsList) {

tv.append(s);

tv.append("\n\n");

}

}

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

switch (requestCode) {

case 101:

if (grantResults.length > 0 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {

readTheContacts();

} else {

Toast.makeText(this, " 你拒绝了读取联系人权限 ", Toast.LENGTH_SHORT).show();

finish();

}

break;

}

}

}

Kotlin 代码

class ContactsActivity : AppCompatActivity() {

private lateinit var tv: TextView

private val contractsList = LinkedList()

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_contacts)

tv = findViewById(R.id.contactsTv)

mayReadTheContacts()

}

private fun mayReadTheContacts() {

if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(

this,

Manifest.permission.READ_CONTACTS

)

) {

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 101)

} else {

readTheContacts()

}

}

/**

* 读取联系人数据

*/

private fun readTheContacts() {

contractsList.clear()

contentResolver.query(

ContactsContract.Contacts.CONTENT_URI,

null, null, null, null

)?.apply {

// 遍历每一条联系人的数据

while (moveToNext()) {

// 读取联系人数据在系统中的id,以及联系人名称

val id = getString(getColumnIndex(ContactsContract.Contacts._ID))

val name = getString(getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))

// 读取联系人的电话号码

val numbers = StringBuilder()

contentResolver.query(

ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = $id", null, null

)?.apply {

while (moveToNext()) {

val num =

getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))

numbers.append(num).append(" ")

}

close()

}

// 读取联系人的邮箱

val address = StringBuilder()

contentResolver.query(

ContactsContract.CommonDataKinds.Email.CONTENT_URI,

null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = $id", null, null

)?.apply {

while (moveToNext()) {

val mail =

getString(getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA))

address.append(mail).append(" ")

}

close()

}

contractsList.add("[$id] $name\n$numbers\n$address")

}

close()

// 界面显示联系人的数据

updateUI()

}

}

private fun updateUI() {

tv.text = ""

val it = contractsList.listIterator()

while (it.hasNext()) {

tv.append(it.next())

tv.append("\n\n")

}

}

override fun onRequestPermissionsResult(

requestCode: Int,

permissions: Array,

grantResults: IntArray

) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults)

when (requestCode) {

101 -> {

if (grantResults.isNotEmpty() && PackageManager.PERMISSION_GRANTED == grantResults[0]) {

readTheContacts()

} else {

Toast.makeText(this, " 你拒绝了读取联系人权限 ", Toast.LENGTH_SHORT).show()

finish()

}

}

}

}

}

函数 mayReadTheContacts() 首先判断用户是否授权读取联系人信息,得到授权之后再去读取联系人信息;

函数 onRequestPermissionsResult() 是用户授权/拒绝的回调;

函数 readTheContacts() 实现了读取联系人信息,然后调用 updateUI() 在界面上显示出来;

Android 使用 ContentResolver 对象来操作共享数据,Activity提供了 getContentResolver() 函数来获取该对象;

使用ContentResolver 的 query()函数来查询数据。

用到的常量说明:

ContactsContract.Contacts.CONTENT_URI,管理联系人的 Uri;

ContactsContract.CommonDataKinds.Phone.CONTENT_URI,管理联系人手机号码的 Uri;

ContactsContract.CommonDataKinds.Email.CONTENT_URI,管理联系人邮箱账号的 Uri;

项目运行

首先我们需要在模拟器中添加联系人数据,假如已经有联系人数据了可以忽略这一步;

运行项目;点击项目主页的按钮,跳转至新页面;系统弹窗请求授权读取联系人数据,我们点击允许;

然后页面显示出系统联系人的数据:

项目代码地址

Java 版:

https://github.com/BethelDEV/shaguaAndroid/tree/main/javaSource/ContentProviderSample

Kotlin 版:

https://github.com/BethelDEV/shaguaAndroid/tree/main/kotlinSource/ContentProviderSample