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 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路11 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
勇哥java实战分享12 分钟前
短信平台 Pro 版本 ,比开源版本更强大
后端
是一个Bug14 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213816 分钟前
React面向组件编程
开发语言·前端·javascript
学历真的很重要16 分钟前
LangChain V1.0 Context Engineering(上下文工程)详细指南
人工智能·后端·学习·语言模型·面试·职场和发展·langchain
计算机毕设VX:Fegn089519 分钟前
计算机毕业设计|基于springboot + vue二手家电管理系统(源码+数据库+文档)
vue.js·spring boot·后端·课程设计
上进小菜猪36 分钟前
基于 YOLOv8 的智能杂草检测识别实战 [目标检测完整源码]
后端
持续升级打怪中38 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路41 分钟前
GDAL 实现矢量合并
前端