五、ContentProvider相关
ContentProvider内容提供者: 负责数据存取,常用于APP进数据共享,跨进程数据存取等…比如读取相册,读取联系人,都是ContentProvider来实现的
- **1.**我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信、相册等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了!
- **2.**我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露!
1.权限申请
从android6.0开始,凡是涉及用户隐私的权限(读写短信,读写联系人,拍摄,录音等等),都需要运行时申请,弹窗提醒用户是否授权。用户不授权则无法继续操作
首先在AndroidManifest.xml中声明读取通信录的权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
运行时动态申请权限,请求用户授权
class TestContentProviderActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//判断读取通讯录的允许
if(ActivityCompat.checkSelfPermission(this , android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
//如果未授权
ActivityCompat.requestPermissions(
this ,
arrayOf(android.Manifest.permission.READ_CONTACTS) ,
100)
}else{
getContacts() //读取联系人
}
}
//读取联系人
private fun getContacts() {
Toast.makeText(this, "getContacts", Toast.LENGTH_SHORT).show()
}
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_CONTACTS){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ //表示授予权限
getContacts()
}else{
Toast.makeText(this,"读取通讯录的权限被拒绝,程序将无法继续工作",Toast.LENGTH_LONG).show()
}
}
}
}
2.读取通讯录联系人
表名 | 说明 |
---|---|
content://com.android.contacts/data/phones | 读取联系人的表的名字 |
字段 | 说明 |
---|---|
display_name | 用户名 |
Data1 | 手机号 |
//读取联系人
@SuppressLint("Range")
private fun getContacts() {
//查询对象
val resolver = contentResolver
//格式化一个uri
val uri = Uri.parse("content://com.android.contacts/data/phones")
//得到一个游标
val cursor = resolver.query(uri, null, null, null, null)?:return
while (cursor.moveToNext()) {
//获取联系人名字和号码
val displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
val phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
Log.e("ContentProvider", "姓名:$displayName")
Log.e("ContentProvider", "号码:$phoneNumber")
Log.e("ContentProvider", "======================")
}
cursor.close() //游标关闭!!
}
3.通信录插入联系人
表名 | 说明 |
---|---|
content://com.android.contacts/data/data | 插入联系人的表的名字 |
content://com.android.contacts/data/raw_contacts | 插入联系人的原始表的名字 |
//插入联系人
private fun insertContact() {
/*
* 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
* 这时后面插入data表的数据,才能使插入的联系人在通讯录里面可见
*/
val resolver = contentResolver
val values = ContentValues()
val rawContactUri = contentResolver!!.insert(ContactsContract.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 , CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) //内容类型
values.put(CommonDataKinds.StructuredName.GIVEN_NAME , "some_name")
resolver.insert(ContactsContract.Data.CONTENT_URI , values)
//往data表里写入电话数据
values.clear() //先把可能存在的数据清空
values.put(ContactsContract.Data.RAW_CONTACT_ID , rawContactId)
values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.Phone.CONTENT_ITEM_TYPE) //内容类型
values.put(CommonDataKinds.Phone.NUMBER , "1231231234")
values.put(CommonDataKinds.Phone.TYPE , CommonDataKinds.Phone.TYPE_MOBILE) //手机号
resolver.insert(ContactsContract.Data.CONTENT_URI , values)
//往data表里写入Email的数据
values.clear() //先把可能存在的数据清空
values.put(ContactsContract.Data.RAW_CONTACT_ID , rawContactId)
values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.Email.CONTENT_ITEM_TYPE) //内容类型
values.put(CommonDataKinds.Email.DATA , "some_name@xx.com")
values.put(CommonDataKinds.Email.TYPE , CommonDataKinds.Email.TYPE_HOME) //家庭邮箱
resolver.insert(ContactsContract.Data.CONTENT_URI , values)
}
4.更新联系人信息
- 根据手机号获取联系人在通讯录的contact_id
@SuppressLint("Range")
fun getContactIdByPhone(phone : Long) : String?{
val uri = Uri.parse("content://com.android.contacts/data/phones/filter/$phone")
val resolver = contentResolver
val cursor = resolver.query(uri, arrayOf(ContactsContract.Data.CONTACT_ID), null, null, null)?:return null
if (cursor.moveToNext()){
val contractId = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
return contractId
}
return null
}
- 更新联系人的姓名
//更新联系人
private fun updateContact() {
val contractId = getContactIdByPhone(234524)
if(contractId == null){
Toast.makeText(this , "联系人不存在,无法更新" , Toast.LENGTH_LONG).show()
return
}
val values = ContentValues()
values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
values.put(CommonDataKinds.StructuredName.GIVEN_NAME, "new_name")
contentResolver.update(
ContactsContract.Data.CONTENT_URI,
values,
"${ContactsContract.Data.CONTACT_ID}=?",
arrayOf(contractId)
)
}
5.删除联系人
- 根据姓名删除联系人
val ret = contentResolver.delete(
ContactsContract.RawContacts.CONTENT_URI,
CommonDataKinds.Phone.DISPLAY_NAME + "=?",
arrayOf("some_name")
)
if(ret>0){
Toast.makeText(this,"删除成功", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show()
}
- 根据手机号删除联系人
val contact_id = getContactIdByPhone(1111)
contentResolver.delete(RawContacts.CONTENT_URI,CommonDataKinds.Phone.CONTACT_ID+"=?", arrayOf(contact_id));
6.读取收件箱所有短信
字段 | 说明 |
---|---|
address | 收件人地址,即手机号,如+8613811810000 |
person | 人物 |
date | 日期,long型,如1256539465022,可以对日期显示格式进行设置 |
protocol | 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信 |
read | 是否阅读0:未读,1:已读 |
type | 短信类型1: 接收到的短信,2:发出的短信 |
body | 短信具体内容 |
需要动态获取权限
<uses-permission android:name="android.permission.READ_SMS"/>
private fun getMessage() {
val uri = Uri.parse("content://sms/")
val resolver = contentResolver
//查询短信的 发件人地址 日期 短信类型 短信具体内容
val cursor = resolver.query(uri, arrayOf("address", "address", "type", "body"), null, null, null)?:return
while (cursor.moveToNext()){
val address = cursor.getString(0)
val data = cursor.getString(1)
val type = cursor.getString(2)
val body = cursor.getString(3)
Log.e("ContentProvider","收件人 $address")
Log.e("ContentProvider","类型时间 [$type]:$data")
Log.e("ContentProvider","短信内容 $body")
Log.e("ContentProvider","-----------------------------")
}
cursor.close() //关闭游标!!
}
短信相关的其它操作uri
content://sms/ 所有短信
content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱
content://sms/failed 发送失败
content://sms/queued 待发送列表