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

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

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

项目代码地址

相关推荐
雨白7 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹8 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空10 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日12 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟16 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡17 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0017 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体