Cursor 操作 → Room DAO

Cursor 操作 → Room DAO

老写法(Java + Cursor)

java 复制代码
// 查询
Cursor cursor = db.rawQuery("SELECT * FROM item", null);
List<Item> items = new ArrayList<>();
while (cursor.moveToNext()) {
    long id = cursor.getLong(cursor.getColumnIndex("id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    double price = cursor.getDouble(cursor.getColumnIndex("price"));
    items.add(new Item(id, name, price));
}
cursor.close();

// 统计
Cursor countCursor = db.rawQuery("SELECT COUNT(*) FROM item", null);
countCursor.moveToFirst();
int count = countCursor.getInt(0);
countCursor.close();

// 分页
Cursor pageCursor = db.rawQuery(
        "SELECT * FROM item LIMIT ? OFFSET ?",
        new String[]{String.valueOf(20), String.valueOf(offset)});
// ...遍历、关闭

问题在哪里

getColumnIndex 依赖字符串,字段名写错返回 -1,然后 getString(-1) 直接崩。每个查询都要手动遍历 Cursor、手动 close(),忘关就泄漏。LIMIT ? OFFSET ? 这种 SQL 拼接容易出错且可读性差。

新写法(Room DAO)

kotlin 复制代码
@Dao
interface ItemDao {
    // 基本查询
    @Query("SELECT * FROM item")
    suspend fun getAll(): List<Item>

    // 按条件查询
    @Query("SELECT * FROM item WHERE price > :minPrice")
    suspend fun getByPrice(minPrice: Double): List<Item>

    // 统计
    @Query("SELECT COUNT(*) FROM item")
    suspend fun count(): Int

    // 分页 --- 用 PagingSource
    @Query("SELECT * FROM item ORDER BY id ASC")
    fun pagingSource(): PagingSource<Int, Item>

    // 返回 Flow 自动监听数据变化
    @Query("SELECT * FROM item ORDER BY name ASC")
    fun getAllFlow(): Flow<List<Item>>
}

使用:

kotlin 复制代码
// 普通查询
viewModelScope.launch(Dispatchers.IO) {
    val items = db.itemDao().getAll()
    val count = db.itemDao().count()
}

// Flow 自动更新
db.itemDao().getAllFlow()
        .asLiveData()
        .observe(viewLifecycleOwner) { items -> adapter.submitList(items) }

一句话注意

Room 的 @Query 在编译期验证 SQL 语法,表名或字段名写错了编译直接报错。这是 Room 相对手写 Cursor 最大的安全优势。

返回类型为 Flow 的查询,Room 会在数据变更时自动重新发出查询结果。底层是通过数据库的触发器实现的,不是轮询,所以不浪费性能。但注意 Flow 查询不支持 suspend,这两个互斥------要么一次性返回用 suspend,要么持续监听用 Flow

cursor.getColumnIndex() 的失败模式是静默的(返回 -1),而 Room 的错误是编译期的,这也是迁移到 Room 最实在的好处。


Java Android 老项目迁移系列,持续更新中。

相关推荐
成都大菠萝4 小时前
Android Car CarProperty 车辆信号链路
android
敲代码的鱼4 小时前
PDF 预览与签名批注写回 支持安卓 iOS 鸿蒙 UTS插件
android·前端·ios
时光足迹6 小时前
uni-app 视频通话实战:康复师与患者视频问诊的 6 个致命 Bug 与解决方案
android·ios·uni-app
像我这样帅的人丶你还6 小时前
Java 后端详解(四):分页与搜索
java·javascript·后端
她的男孩6 小时前
数据权限为什么不能只靠注解?Forge 的 Mapper 层 SQL 改写源码拆解
java·后端·架构
tntxia7 小时前
Mybatis的日志输入
java
亦暖筑序8 小时前
Java 8老系统Browser Agent实战:三层拦截把AI操作后台变成可审计流程
java·后端·设计模式
Coffeeee10 小时前
闲聊几句,Android老哥们,你们多久没做技改需求了
android·程序员·代码规范
萝卜er11 小时前
Fragment 生命周期与状态恢复-《Android深水区(四)》
android
萝卜er11 小时前
Intent 显式、隐式与 PendingIntent-《Android深水区(五)》
android