如何使用Jetpack Glance组件在小组件中展示Room本地数据库中的笔记数据?
如何使用Jetpack Glance组件在小组件中展示Room本地数据库中的笔记数据?
咱们得先搞清楚:Glance组件和普通App里的Compose不一样,它没法直接用咱们平时依赖注入的ViewModel(毕竟小组件跑在系统进程里,依赖逻辑不通),所以得换个思路——用Glance自带的状态存储来保存笔记数据,再在数据库变化时主动触发小组件刷新。
接下来一步步改你的代码:
1. 让小组件能拿到Room数据(修改AppWidgetReceiver)
你的AppWidgetReceiver已经加了@AndroidEntryPoint,刚好可以直接注入你的EntityRepoImp。咱们在系统触发小组件更新时,从Room拉最新数据,存到Glance的偏好状态里:
@AndroidEntryPoint class AppWidgetReceiver : GlanceAppWidgetReceiver() { @Inject lateinit var repo: EntityRepoImp override val glanceAppWidget: GlanceAppWidget = AppWidget() override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { super.onUpdate(context, appWidgetManager, appWidgetIds) // 开协程在IO线程拿数据,避免阻塞主线程 CoroutineScope(Dispatchers.IO).launch { repo.getAllNotesById.collect { notes -> // 给每个已添加的小组件更新状态 appWidgetIds.forEach { widgetId -> glanceAppWidget.update(context, GlanceId(widgetId)) { preferences -> // 把笔记列表转成JSON字符串存起来(需要Gson序列化) val notesJson = Gson().toJson(notes) preferences.edit { it.putString("saved_notes", notesJson) } } } } } } }
2. 在小组件UI里读取并展示数据(修改AppWidget类)
现在数据已经存在Glance的偏好里了,咱们在Content里把它读出来,解析成笔记列表,再渲染成UI:
class AppWidget : GlanceAppWidget() { // 指定用Glance的偏好存储来保存状态 override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition @Composable override fun Content() { // 拿到存储的JSON字符串 val notesJson = currentState<String?>("saved_notes") // 解析成笔记列表,为空的话默认显示空列表 val notes = notesJson?.let { Gson().fromJson(it, object : TypeToken<List<Entity>>() {}.type) } ?: emptyList() // 用LazyColumn展示所有笔记,适配小组件的滚动需求 LazyColumn( modifier = GlanceModifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 8.dp) ) { items(notes) { note -> // 替换成你的Entity实际字段,比如标题、内容摘要 Text( text = note.title, modifier = GlanceModifier.padding(bottom = 8.dp), style = TextStyle(fontSize = 16.sp) ) } } } }
3. 数据库变化时自动刷新小组件
现在小组件只能在系统触发更新时拿数据,咱们得让它在用户增删改笔记时自动刷新。可以在你的AppWidgetVM里,当Flow收到新数据时发送广播:
先给ViewModel加上Application依赖(用来获取Context):
@HiltViewModel class AppWidgetVM @Inject constructor( private val repo: EntityRepoImp, private val application: Application // 新增这个参数 ): ViewModel() { private val _allNotesById = MutableStateFlow<List<Entity>>(emptyList()) val allNotesById: StateFlow<List<Entity>> get() = _allNotesById.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(), initialValue = listOf() ) init { viewModelScope.launch(Dispatchers.IO) { repo.getAllNotesById.collect { notes -> _allNotesById.value = notes // 发送广播通知所有小组件刷新 val updateIntent = Intent(application, AppWidgetReceiver::class.java).apply { action = AppWidgetManager.ACTION_APPWIDGET_UPDATE // 获取所有已添加的小组件ID val widgetIds = AppWidgetManager.getInstance(application).getAppWidgetIds( ComponentName(application, AppWidgetReceiver::class.java) ) putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds) } application.sendBroadcast(updateIntent) } } } }
小提醒
- 别忘了加Gson依赖:在你的
build.gradle里添加implementation 'com.google.code.gson:gson:2.10.1',不然没法序列化数据 - 如果笔记数量很多,别在小组件里展示全部内容,挑关键信息(比如标题)就行,避免UI卡顿或者超出小组件尺寸限制
这样改完之后,你的Glance小组件就能实时同步Room里的本地笔记数据啦!
备注:内容来源于stack exchange,提问作者Youn Tivoli
相关产品推荐
相关产品推荐

