Android四大组件之ContentProvider篇

514 阅读2分钟

引言

上篇文章总结了BroadcastReceiver,这篇文章来复习下四大组件的最后一个ContentProvider,ContentProvider能将应用程序内部存储的数据通过其所提供的访问方式分享给其它应用程序使用,让我们先来看看系统提供的ContentProvider

一、系统提供的ContentProvider

系统提供了各式各样的ContentProvider,比如通讯录、短信等等,这里我们以获取通讯录中联系人信息为例

data class Contact(val id: Int, val name: String, val phone: String)

private fun getContacts(): List<Contact> {
    val cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null,
            null, null, null)
    val contacts = ArrayList<Contact>()
    if (cursor != null) {
        while (cursor.moveToNext()) {
            val id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID))
            val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
            // 再根据ID查出电话
            val phoneCursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null)
            if (phoneCursor != null) {
                while (phoneCursor.moveToNext()) {
                    val phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(
                            ContactsContract.CommonDataKinds.Phone.NUMBER))
                    contacts.add(Contact(id, name, phoneNumber))
                }
                phoneCursor.close()
            }
        }
        cursor.close()
    }
    return contacts
}
// 所需权限
<uses-permission android:name="android.permission.READ_CONTACTS" />

这里先通过contentResolver.query查询出id和name,然后再根据id去另一张表中查询phoneNumber

二、自定义ContentProvider

我们需要创建一个ContentProvider的子类,重写以下几个方法

  • onCreate 在应用程序启动时会调用,因为其运行在主线程所有不能执行耗时任务,不然可能会使程序启动过慢,或者直接ANR
  • insert 在子线程运行,外界调用ContentResolver.insert时调用
  • query 在子线程运行,外界调用ContentResolver.query时调用
  • update 在子线程运行,外界调用ContentResolver.update时调用
  • delete 在子线程运行,外界调用ContentResolver.delete时调用
  • getType 如果该Uri表示一条记录返回值应该以vnd.android.cursor.item开头,多条记录返回值应该以vnd.android.cursor.dir/开头

然后再在清单文件中进行配置

<provider
    android:authorities="com.hfw.provider"
    android:exported="true"
    android:name=".MyProvider"/>

这里的主机名确定了什么Uri能够调用该ContentProvider,比如这里设置了com.hfw.provider,那么只有以content://com.hfw.provider开头的Uri才会调用该ContentProvider,主机名后面还可以跟上要操作的表明、或者某些条件(自己约定好就行)

  • 例如 content://com.hfw.provider/user 表示要操作User表中所有的数据、content://com.hfw.provider/user/zhangsan 表示要操作User表中name为zhangsan的记录