Android ContentResolver地点增删改查详解

Android 中 ContentResolver 的增删改查详解

ContentResolver 是 Android 提供的 API,用于在不同应用程序之间访问和操作数据,通常与 ContentProvider 一起使用。它提供 增(insert)、删(delete)、改(update)、查(query) 操作,常见于访问系统数据库(如通讯录、媒体库等)或应用自定义的数据库(如日记本、笔记等)。


📌 使用 ContentResolver 的步骤

  1. 确定 ContentProvider 提供的数据 URIcontent:// 格式)
  2. 获取 ContentResolver 对象
  3. 执行增、删、改、查操作
  4. 处理权限(如果是访问系统数据)
  5. 关闭 Cursor 以释放资源(仅 query 需要)

💡 1. 获取 ContentResolver

ActivityFragment 中:

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) UriContentValues
更新 update(uri, values, selection, selectionArgs) UriContentValues,条件
删除 delete(uri, selection, selectionArgs) Uri,条件

💡 你是要操作自己的 ContentProvider 还是访问系统数据?如果是日记本的 ContentProvider,可以一起设计 URI 和数据库结构。

相关推荐
涡能增压发动积2 天前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o2 天前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨2 天前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz2 天前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg3213212 天前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶2 天前
前端交互规范(Web 端)
前端
tyung2 天前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald2 天前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU7290352 天前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing2 天前
Page-agent MCP结构
前端·人工智能