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. 项目运行

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

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

项目代码地址

相关推荐
mmsx4 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
众拾达人7 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
吃着火锅x唱着歌8 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
_Shirley9 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
hedalei11 小时前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576
锋风Fengfeng11 小时前
安卓多渠道apk配置不同签名
android
枫_feng12 小时前
AOSP开发环境配置
android·安卓
叶羽西12 小时前
Android Studio打开一个外部的Android app程序
android·ide·android studio
qq_1715388513 小时前
利用Spring Cloud Gateway Predicate优化微服务路由策略
android·javascript·微服务
Vincent(朱志强)15 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式