Android 中 ContentResolver
的增删改查详解
ContentResolver
是 Android 提供的 API,用于在不同应用程序之间访问和操作数据,通常与 ContentProvider
一起使用。它提供 增(insert)、删(delete)、改(update)、查(query) 操作,常见于访问系统数据库(如通讯录、媒体库等)或应用自定义的数据库(如日记本、笔记等)。
📌 使用 ContentResolver
的步骤
- 确定
ContentProvider
提供的数据 URI (content://
格式) - 获取
ContentResolver
对象 - 执行增、删、改、查操作
- 处理权限(如果是访问系统数据)
- 关闭
Cursor
以释放资源(仅query
需要)
💡 1. 获取 ContentResolver
在 Activity
或 Fragment
中:
ini
val contentResolver = context.contentResolver
在 Service
中:
ini
val contentResolver = applicationContext.contentResolver
🔍 2. 查询数据(query)
查询 ContentProvider
提供的数据,返回 Cursor
,需手动遍历和关闭。
示例:查询日记
kotlin
// 1. 目标 ContentProvider 的 URI
val uri = Uri.parse("content://com.example.provider/diary")
//构造 content:// 开头的 Uri,它用于标识数据库中的某条数据。
// 2. 查询的字段(列)
val projection = arrayOf("id", "title", "date")
// 3. 查询条件(WHERE)
val selection = "title LIKE ?"
val selectionArgs = arrayOf("%心情%") // 查询包含"心情"的日记
//这表示查询 title 列,要求 title 的内容包含"心情"两个字。
//LIKE 是 SQL 语法,用于进行模糊查询。
//? 是占位符,用来防止 SQL 注入,具体值由 selectionArgs 提供。
// 4. 排序方式
val sortOrder = "date DESC"
// 5. 执行查询
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
cursor?.use {
while (it.moveToNext()) {
val id = it.getInt(it.getColumnIndexOrThrow("id"))
val title = it.getString(it.getColumnIndexOrThrow("title"))
val date = it.getLong(it.getColumnIndexOrThrow("date"))
println("ID: $id, Title: $title, Date: $date")
}
} // `use` 语法确保 Cursor 关闭
🔹 注意事项:
- 查询时使用
LIKE
支持模糊匹配,?
代表参数占位符 - 使用
Cursor
需要调用.moveToNext()
逐行读取 - 关闭
Cursor
以释放资源
📝 3. 插入数据(insert)
用于新增数据,返回新数据的 Uri
。
示例:新增日记
scss
val uri = Uri.parse("content://com.example.provider/diary")
// 1. 创建 ContentValues,存储字段和值
val values = ContentValues().apply {
put("title", "今日心情")
put("content", "今天是个好天气")
put("date", System.currentTimeMillis())
}
// 2. 调用 insert 方法
val newUri = contentResolver.insert(uri, values)
// 3. 判断插入结果
if (newUri != null) {
println("插入成功,URI: $newUri")
} else {
println("插入失败")
}
🔹 注意事项:
ContentValues
类似Map
,用于存储字段和值insert()
返回新数据的Uri
,失败时返回null
- newUri:表示新插入的数据的 URI ,用于后续操作。如果插入失败,返回
null
。
✏ 4. 更新数据(update)
用于修改已有数据,返回影响的行数。
示例:更新日记内容
kotlin
val uri = Uri.parse("content://com.example.provider/diary")
// 1. 创建 ContentValues,存储更新的字段和值
val values = ContentValues().apply {
put("content", "更新后的日记内容")
}
// 2. 更新条件
val selection = "id = ?"
val selectionArgs = arrayOf("1") // 只更新 ID 为 1 的日记
// 3. 执行 update
val rowsUpdated = contentResolver.update(uri, values, selection, selectionArgs)
println("更新了 $rowsUpdated 条数据")
🔹 注意事项:
selection
是 SQL 语法的WHERE
子句update()
返回更新的行数,可能为0
(表示数据未找到)
🗑 5. 删除数据(delete)
用于删除数据,返回删除的行数。
示例:删除指定日记
kotlin
val uri = Uri.parse("content://com.example.provider/diary")
// 1. 删除条件
val selection = "id = ?"
val selectionArgs = arrayOf("1") // 只删除 ID 为 1 的日记
// 2. 执行删除
val rowsDeleted = contentResolver.delete(uri, selection, selectionArgs)
println("删除了 $rowsDeleted 条数据")
🔹 注意事项:
delete()
返回删除的行数- 不提供
selection
则删除所有数据(谨慎)
📖 6. 访问系统 ContentProvider
示例
📌 读取联系人
kotlin
val uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
val cursor = contentResolver.query(uri, null, null, null, null)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
val phone = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER))
println("联系人: $name, 电话: $phone")
}
}
📌 读取相册
kotlin
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(uri, projection, null, null, null)
cursor?.use {
while (it.moveToNext()) {
val imagePath = it.getString(it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
println("图片路径: $imagePath")
}
}
🔒 7. 处理权限
如果访问系统 ContentProvider
(如通讯录、相册等),需申请权限:
在 AndroidManifest.xml
申请权限
ini
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
动态请求权限(Android 6.0+)
kotlin
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 1)
}
📌 总结
操作 | 方法名 | 主要参数 |
---|---|---|
查询 | query(uri, projection, selection, selectionArgs, sortOrder) |
Uri ,字段数组,查询条件,排序 |
插入 | insert(uri, values) |
Uri ,ContentValues |
更新 | update(uri, values, selection, selectionArgs) |
Uri ,ContentValues ,条件 |
删除 | delete(uri, selection, selectionArgs) |
Uri ,条件 |
💡 你是要操作自己的 ContentProvider
还是访问系统数据?如果是日记本的 ContentProvider
,可以一起设计 URI 和数据库结构。