ContentProvider
主要用于不同应用程序之间共享数据,比如联系人、短信、媒体库等都实现了跨应用数据共享功能。 ContentProvider
在提供数据共享的同时还能保证被访问数据的安全性。
代码演示"读取联系人"
-
创建一个项目
ContentProviderSample
-
新建
Activity
,名为ContactsActivity
-
配置
AndroidManifest.xml
,添加读取联系人权限<uses-permission android:name="android.permission.READ_CONTACTS" />
-
编辑布局文件
activity_main.xml
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="30dp">
<Button
android:id="@+id/contactsBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="read contacts" />
</LinearLayout>
增加了一个按钮,用于启动ContactsActivity
。
- 编辑
MainActivity
Java 代码
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 代码
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
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="30dp">
<TextView
android:id="@+id/contactsTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:hint="contacts" />
</LinearLayout>
TextView
用于呈现读取到的联系人数据,这里简化处理了。
- 编辑
ContactsActivity
Java 代码
java
public class ContactsActivity extends AppCompatActivity {
private TextView tv;
private final List<String> 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 代码
kotlin
class ContactsActivity : AppCompatActivity() {
private lateinit var tv: TextView
private val contractsList = LinkedList<String>()
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<out String>,
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 版: github.com/BethelDEV/s...
Kotlin 版: github.com/BethelDEV/s...