ContentProvider必会必知

本节给大家带来的是Android四大组件中的最后一个——ContentProvider(内容提供者),可能部分读者 有疑问了,说到这个ContentProvider,我们什么时候 会用到他呢?有下面这两种:

  • 1.我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信、相册等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了!
  • 2.我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露!

好像好流弊的样子,其实用起来也很简单

ContentProvider

权限申请

从android6.0开始,凡是涉及用户隐私的权限(读写短信,读写联系人,拍摄,录音等等),都需要运行时申请,弹窗提醒用户是否授权。用户不授权则无法继续操作,而且今年工信部对于违规收集,申请用户权限的APP查的非常严格,不定期抽查,抽查有问题的必须按期整改,否则强制下架。

首先在AndroidManifest.xml中声明读取短信的权限

<uses-permission android:name="android.permission.READ_CONTACTS"/>

运行时动态申请权限,请求用户授权

  • ActivityCompat.checkSelfPermission():检查权限是否已授权,如果没授权则需要向用户申请
  • ActivityCompat.requestPermissions():发起权限申请,会弹出对话框permission

  • ActivityCompat.shouldShowRequestPermissionRationale(): 检查用户是否已经永久拒绝,如果用户已永久拒绝某个权限的申请,即便再调用ActivityCompat.requestPermissions,系统也不会弹框向用户申请了。此时需要自己弹对话框,引导用户去开启授权

  • onRequestPermissionsResult:处理权限授权的结果

  • 完整的权限申请案例

class PermissionActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (ActivityCompat.checkSelfPermission(this,
                android.Manifest.permission.READ_SMS
            ) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions( this, arrayOf(android.Manifest.permission.READ_SMS),100)
        } else {
            // 如果已授权则可以直接读取通讯录了
            getContacts()
        }
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
         // 处理权限申请的结果
        if (requestCode==100&&permissions[0]== android.Manifest.permission.READ_SMS){
            if (grantResults[0]==PackageManager.PERMISSION_GRANTED){
                 // 如果请求结果是授权了,则可以继续操作
                 getContacts()
            }else{
                // 如果本次申请权限,未得到授权,则toast提示,终止读取的操作。
                Toast.makeText(this, "通讯录权限被拒绝,无法读取联系人", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

读取通讯录联系人

表名 说明
content://com.android.contacts/data/phones 读取联系人的表的名字
字段 说明
display_name 用户名
Data1 手机号
 fun getContacts() {
        //①查询raw_contacts表获得联系人的id
        val resolver = contentResolver
        val uri =Uri.parse("content://com.android.contacts/data/phones")
        //查询联系人数据
        val cursor = resolver.query(uri, null, null, null, null)!!
        while (cursor.moveToNext()) {
            //获取联系人姓名,手机号码
            val cName: String =
                cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
            val cNum: String =
                cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
            Log.e("ContentProvider", "姓名:$cName")
            Log.e("ContentProvider", "号码:$cNum")
            Log.e("ContentProvider", "======================")
        }
        cursor.close()
    }

运行结果:

姓名:china unicom
号码:10010
======================
姓名:zhang san
号码:10086

通信录插入联系人

  • AndroidManifest.xml声明权限
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
  • 插入联系人
表名 说明
content://com.android.contacts/data/data 插入联系人的表的名字
content://com.android.contacts/data/raw_contacts 插入联系人的原始表的名字
fun insertContact() {
        val values = ContentValues()
        /*
         * 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
         * 这时后面插入data表的数据,才能使插入的联系人在通讯录里面可见
         */
        val rawContactUri: Uri = contentResolver!!.insert(RawContacts.CONTENT_URI, values)!!
        val rawContactId = ContentUris.parseId(rawContactUri)

        //往data表里写入姓名数据
        values.clear()
        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
        values.put(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) //内容类型
        values.put(StructuredName.GIVEN_NAME, "李四")
        contentResolver.insert(ContactsContract.Data.CONTENT_URI, values)

        //往data表里写入电话数据
        values.clear()
        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
        values.put(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
        values.put(Phone.NUMBER, "13921009789")
        values.put(Phone.TYPE, Phone.TYPE_MOBILE)
        contentResolver.insert(ContactsContract.Data.CONTENT_URI, values)

        //往data表里写入Email的数据
        values.clear()
        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
        values.put(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
        values.put(Email.DATA, "lisi@qq.com")
        values.put(Email.TYPE, Email.TYPE_WORK)
        contentResolver
            .insert(ContactsContract.Data.CONTENT_URI, values)
    }

更新联系人信息

  • 根据手机号获取联系人在通讯录的contact_id
fun getContactIdByPhone(phone:Long): String {
        val uri =Uri.parse("content://com.android.contacts/data/phones/filter/$phone")
        val cursor = contentResolver.query(
            uri,
            arrayOf(ContactsContract.Data.CONTACT_ID),
            null,
            null,
            null
        )!! 
        if (cursor.moveToFirst()) {
            return cursor.getString(0)
        }
        return ""
    }
  • 更新联系人的姓名
fun update(){
   val contact_id = getContactIdByPhone(100001)
   val values = ContentValues()
   values.put(ContactsContract.Data.MIMETYPE,
            ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
        ) //内容类型
        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "lisi")
        contentResolver.update(
            Uri.parse("content://com.android.contacts/data"),
            values,
            "${ContactsContract.Data.CONTACT_ID}=?",
            arrayOf(contact_id)
        )
}

删除联系人

  • 根据姓名删除联系人
contentResolver.delete(RawContacts.CONTENT_URI,CommonDataKinds.Phone.DISPLAY_NAME+"=?", arrayOf("test"));
  • 根据手机号删除联系人
val contact_id = getContactIdByPhone(1111)

contentResolver.delete(RawContacts.CONTENT_URI,CommonDataKinds.Phone.CONTACT_ID+"=?", arrayOf(contact_id));

读取收件箱所有短信

字段 说明
address 发件人地址,即手机号,如+8613811810000
person 发件人地址,即手机号,如+8613811810000
date 日期,long型,如1256539465022,可以对日期显示格式进行设置
protocol 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信
read 是否阅读0:未读,1:已读
type 短信类型1: 接收到的短信,2:发出的短信
body 短信具体内容
 fun getMsgs() {
        val uri: Uri = Uri.parse("content://sms/")
        val resolver = contentResolver
        //获取的是哪些列的信息
        val cursor: Cursor = resolver.query(
            uri,
            arrayOf("address", "date", "type", "body"),
            null,
            null,
            null
        )!!
        while (cursor.moveToNext()) {
            val address: String = cursor.getString(0)
            val date: String = cursor.getString(1)
            val type: String = cursor.getString(2)
            val body: String = cursor.getString(3)
            Log.e("ContentProvider", "地址:$address")
            Log.e("ContentProvider", "时间:$date")
            Log.e("ContentProvider", "类型:$type")
            Log.e("ContentProvider", "内容:$body")
            Log.e("ContentProvider", "======================")
        }
        cursor.close()
    }

[!note|style:flat] 短信相关的其它操作uri

content://sms/ 所有短信

content://sms/inbox 收件箱

content://sms/sent 已发送

content://sms/draft 草稿

content://sms/outbox 发件箱

content://sms/failed 发送失败

content://sms/queued 待发送列表

运行结果:

收件人:10010
发送时间:Mon Jun 07 22:13:50 GMT+08:00 2021
短信内容:I'm Android ,I want. to. send message to you 
======================

收件人:10086
发送时间:Mon Jun 07 22:13:53 GMT+08:00 2021
短信内容:this message is send to 10086 by Android

[!note|style:flat]

我们能不能运行时往收件箱里写入一条短信呢?

从5.0开始第三方APP无法插入短信,所以死了这条心吧

powered by GitbookCopyright © songyubao.com 2021 all right reserved。更新于: 23:11:55

results matching ""

    No results matching ""