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 和数据库结构。

相关推荐
回村中年6 分钟前
浏览器 路由详解
前端
Mcband9 分钟前
主流程发起,去除子流程的时长计算问题
java·前端·算法
晓得迷路了9 分钟前
栗子前端技术周刊第 75 期 - Rspack 1.3、React 19.1、Astro 5.6...
前端·javascript·react.js
Kagol10 分钟前
TinyPro 后台管理系统从启动 ➡️ 使用 ➡️ 二开,看这一篇就够了!点赞、收藏⭐,不迷路!
前端·vue.js·nestjs
xiezhr21 分钟前
程序员为什么总是加班?
前端·后端·程序员
猿java21 分钟前
银行系统需要服务降级吗?
java·后端·面试
好_快24 分钟前
Lodash源码阅读-baseIsMatch
前端·javascript·源码阅读
excel25 分钟前
webpack 格式化模块工厂 第 一 节
前端
九筠28 分钟前
python网络爬虫开发实战之Ajax数据提取
前端·爬虫·ajax·网络爬虫
风象南28 分钟前
SpringBoot实现单点登录(SSO)的4种方案
java·spring boot·后端