Android ContentProvider “读取联系人”

ContentProvider主要用于不同应用程序之间共享数据,比如联系人、短信、媒体库等都实现了跨应用数据共享功能。 ContentProvider在提供数据共享的同时还能保证被访问数据的安全性。

代码演示"读取联系人"

  1. 创建一个项目ContentProviderSample

  2. 新建 Activity,名为 ContactsActivity

  3. 配置 AndroidManifest.xml,添加读取联系人权限 <uses-permission android:name="android.permission.READ_CONTACTS" />

  4. 编辑布局文件 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

  1. 编辑 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

  1. 编辑布局文件 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用于呈现读取到的联系人数据,这里简化处理了。

  1. 编辑 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() 函数来获取该对象; 使用ContentResolverquery()函数来查询数据。 用到的常量说明: ContactsContract.Contacts.CONTENT_URI,管理联系人的 Uri; ContactsContract.CommonDataKinds.Phone.CONTENT_URI,管理联系人手机号码的 Uri; ContactsContract.CommonDataKinds.Email.CONTENT_URI,管理联系人邮箱账号的 Uri;

  1. 项目运行

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

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

项目代码地址

相关推荐
xiangxiongfly9151 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢3 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢4 小时前
Android开发报错解决
android
每次的天空5 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空7 小时前
Android学习总结之Binder篇
android·学习·binder
峥嵘life7 小时前
Android 有线网开发调试总结
android
是店小二呀8 小时前
【算法-链表】链表操作技巧:常见算法
android·c++·算法·链表
zhifanxu10 小时前
Kotlin 遍历
android·开发语言·kotlin
追随远方10 小时前
Android NDK版本迭代与FFmpeg交叉编译完全指南
android·ffmpeg
柯南二号20 小时前
Android Studio根目录下创建多个可运行的模块
android·ide·android studio