ContentProvider必会必知
本节给大家带来的是Android四大组件中的最后一个——ContentProvider(内容提供者),可能部分读者 有疑问了,说到这个ContentProvider,我们什么时候 会用到他呢?有下面这两种:
- 1.我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信、相册等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了!
- 2.我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露!
好像好流弊的样子,其实用起来也很简单
权限申请
从android6.0开始,凡是涉及用户隐私的权限(读写短信,读写联系人,拍摄,录音等等),都需要运行时申请,弹窗提醒用户是否授权。用户不授权则无法继续操作,而且今年工信部对于违规收集,申请用户权限的APP查的非常严格,不定期抽查,抽查有问题的必须按期整改,否则强制下架。
首先在AndroidManifest.xml中声明读取短信的权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
运行时动态申请权限,请求用户授权
- ActivityCompat.checkSelfPermission():检查权限是否已授权,如果没授权则需要向用户申请
ActivityCompat.requestPermissions():发起权限申请,会弹出对话框
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无法插入短信,所以死了这条心吧