You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SqlDelight Coroutines Flow无法向Jetpack Glance Widget发射数据

待办Widget数据更新不触发Flow问题排查与修复

问题背景

基于Jetpack Glance开发待办Widget,使用SqlDelight做数据持久化。首次加载数据正常,调试日志能打印;但在provideGlance运行期间向数据库写入新数据时,Flow无新事件触发,Widget也不会重组更新。

相关代码

GlanceWidget实现

override suspend fun provideGlance(context: Context, id: GlanceId) {
    val pageRepository =
        EntryPoints.get(context, PageProviderEntryPoint::class.java).pageRepository()

    val initialPages = pageRepository.getSortedPages(config!!.databaseId, null)

    provideContent {
        val pages by pageRepository.getSortedPagesFlow(config.databaseId, null)
            .collectAsState(initial = initialPages)

        GlanceTheme {
            CheckListLayout(pages)
        }
    }
}

PageRepository实现

fun getSortedPagesFlow(
    databaseId: String, filter: Filter.CompanionFilter?
) = localDatabase.getSortedPagesFlow(databaseId, filter).onEach { println("debug pages count ${it.size}") }


fun getSortedPages(
    databaseId: String, filter: Filter.CompanionFilter?
) = localDatabase.getSortedPages(databaseId, filter)

LocalDatabase实现

override fun getSortedPages(
    databaseId: String,
    filter: Filter.CompanionFilter?
): List<Page> {
    return  dbQuery.selectAllPages(databaseId, ::mapToPage)
            .executeAsList()
            .filter { filter?.evaluate(it) ?: true }
            .sortedBy { Instant.parse(it.lastEditedTime) }.reversed()
}


override fun getSortedPagesFlow(
    databaseId: String,
    filter: Filter.CompanionFilter?
): Flow<List<Page>> {
    return dbQuery.selectAllPages(databaseId, ::mapToPage)
            .asFlow()
            .mapToList(Dispatchers.Main)
            .onEach { println("debug pages count localdb ${it.size}") }
            .map { pages -> pages.filter { filter?.evaluate(it) ?: true }}
            .map { pages -> pages.sortedBy {  Instant.parse(it.lastEditedTime) }.reversed()}

}

问题分析与修复方案

1. 检查SqlDelight查询的监听有效性

SqlDelight的asFlow()仅在查询结果关联的表发生数据变更时触发事件,需确保selectAllPages的SQL查询定义正确,能覆盖目标表的所有变更场景。例如:

selectAllPages:
SELECT * FROM page WHERE database_id = ?;

SqlDelight会自动为这类查询生成带表变更监听的Query实例,确保插入/更新/删除操作能触发Flow事件。

2. 修正Flow的线程调度

数据库操作属于IO任务,mapToList应使用Dispatchers.IO而非Main,避免阻塞主线程同时确保Flow能正确接收数据库变更:

override fun getSortedPagesFlow(
    databaseId: String,
    filter: Filter.CompanionFilter?
): Flow<List<Page>> {
    return dbQuery.selectAllPages(databaseId, ::mapToPage)
            .asFlow()
            .mapToList(Dispatchers.IO)
            .onEach { println("debug pages count localdb ${it.size}") }
            .map { pages -> pages.filter { filter?.evaluate(it) ?: true }}
            .map { pages -> pages.sortedBy { Instant.parse(it.lastEditedTime) }.reversed() }
            .flowOn(Dispatchers.IO)
}

3. 优化Glance中的Flow收集逻辑

无需提前获取初始值,collectAsState可自动处理初始状态,同时确保在Glance的Composition上下文内正确收集Flow:

override suspend fun provideGlance(context: Context, id: GlanceId) {
    val pageRepository = EntryPoints.get(context, PageProviderEntryPoint::class.java).pageRepository()
    val databaseId = config!!.databaseId

    provideContent {
        val pages by pageRepository.getSortedPagesFlow(databaseId, null)
            .collectAsState(initial = emptyList())

        GlanceTheme {
            CheckListLayout(pages)
        }
    }
}

4. 兜底:手动触发Widget更新

若上述调整后仍无效果,可在数据库写入操作完成后,手动调用Glance的更新接口强制刷新Widget:

// 数据写入完成后执行
GlanceWidgetManager(context).updateGlanceWidget(id)

5. 检查SqlDelight版本

确保使用最新稳定版SqlDelight(如2.0.x系列),旧版本可能存在Flow监听的兼容性bug。

内容的提问来源于stack exchange,提问作者Micha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:25:20