Kotlin - StateFlow 不向其收集器发出更新

2024-03-30

我的应用程序中有一个 UserStateModel(数据类)类型的 StateFlow。

private val _userStateFlow: MutableStateFlow<UserStateModel?> = MutableStateFlow(UserStateModel())
val userStateFlow: StateFlow<UserStateModel?> = _userStateFlow

这是用户状态模型

data class UserStateModel(
    val uid: String? = null,
    val username: String? = null,
    val profileImageUrl: String? = null,
    var isLoggedIn: Boolean = false,
    val isPremiumUser: Boolean = false,
    val posts: List<Post>? = listOf()
) 

当我使用新的用户名更新 StateFlow 时,它会将更改发送给收集器并更新 UI。 但是当我更改帖子内的属性时:列表?列表它不会发出更改。 当我更改列表的大小时,它会更改,而当我更改索引 0 处的帖子的 name 属性时,它不会更改。 如何检测 Data 类的子属性的更改?

现在我使用一个丑陋的解决方法,我补充道

val updateErrorWorkaround: Int = 0 

到 UserStateModel 数据类并将其加一以便收集器收到通知

P.s 我正在使用 MVVM + Clean Architecture 和 Jetpack Compose

EDIT这是我的帖子模型:

data class Post(
    val id: Int,
    val name: String, 
    val tags: MutableList<Tag>? = null

)

以下是我更新 MutableList 的方法:

val posts = userStateFlow.value?.posts
posts.get(index).tags?.add(myNewTag)
_userStateFlow.value = userStateFlow.value?.copy(posts = posts)

这些更改不会发送给收集器


StateFlow仅当它检测到值的更改时才发出,它会忽略用相同数据替换该值。为此,它将前一个值与新值进行比较。因此,我们不应该修改已经提供给StateFlow,因为它无法检测到更改。

例如我们设置value to a User(name=John)。然后我们通过修改它来改变同一个用户对象name to James我们设置value到这个“新”用户对象。StateFlow比较“新”User(name=James)及其存储的价值,现在也是User(name=James),所以它没有看到任何变化。

在您的示例中,您创建了一个副本UserStateModel,但在内部你重复使用相同的对象并改变它们。在这种情况下,您添加了一个新项目到tags这个变化影响了旧的UserStateModel以及,所以StateFlow没有检测到变化。

要解决该问题,您需要复制所有已更改的数据,并且不要就地更改任何内容。让所有数据不可变会更安全,所以val and List- 这样你就被迫复印。我变了tags to val tags: List<Tag> = listOf(),那么您的代码可能如下所示:

val posts = userStateFlow.value?.posts!!.toMutableList()
posts[index] = posts[index].copy(tags = posts[index].tags + myNewTag)
userStateFlow.value = userStateFlow.value?.copy(posts = posts)

这里我们不仅创建一个副本UserStateModel。我们也复制posts列出Post我们修改并复制标签列表。

或者,如果这种行为StateFlow对您来说更烦人而不是有帮助,您可以使用SharedFlow它不比较值,而只是发出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin - StateFlow 不向其收集器发出更新 的相关文章

  • 在 Android 中获取联系方式需要花费大量时间?

    您好 目前正在做一个与联系人相关的项目 我正在从联系人中获取详细信息 电子邮件 电话号码和联系人姓名 效果很好 但问题是获取联系方式需要很长时间 超过 1000 个联系人 包括从社交网站同步的联系人 这样我就放了一个Asynchronous
  • onBackPressed 仅关闭 ProgressDialog

    我意识到我的异步任务有一个小问题 我意识到 当我按 Android 设备上的后退按钮来关闭进度对话框和异步任务时 只有我的进度对话框被关闭 而我的异步任务仍在执行 我真的不知道为什么会发生这种情况 所以我只是希望有人能让我回到正确的轨道并帮
  • Android Wear:在手持设备上启动服务

    我正在构建一个 Wear 应用程序 它将与手持设备上的 WearableListenerService 进行通信 但是 我想确保当应用程序在手表上启动时服务已启动并运行 我最初的想法是发送意图或广播消息来启动服务 但是 我一直无法弄清楚如何
  • AdMob 广告未显示

    因此 我使用 Play Services SDK 实施了 AdMob 广告 我已经 按照书本 做了所有事情 但广告不会显示 如果我将 AdView 背景设置为白色 它会显示空白 但不显示广告 我正在使用 Fragments 但我将 AdVi
  • Android Surface 与 Canvas 的关系

    Surface 和 Canvas 之间到底是什么关系 请解释 表面是一个缓冲区 画布保存绘图 视图未附加到画布 也不是表面 窗户被绑在 Surface 和 ViewRoot 询问 随后使用的画布表面 通过要绘制的视图 详细答案你可以阅读这篇
  • 如何在状态更改时更改 Android 切换按钮的文本颜色?

    我的切换按钮对于每个状态都有不同的颜色背景 红色和白色 现在我需要在激活时更改切换按钮文本 红色 白色 的颜色 使用 xml 我无法让它工作 也许有人知道我做错了什么 我的布局 xml 中的按钮
  • 如何在Android中将文件转换为base64(如.pdf、.text)?

    如何将 SD 卡文档 pdf txt 转换为 Base 64 字符串并将字符串发送到服务器 这个方法对我有用 String encodeFileToBase64Binary encodeFileToBase64Binary yourFile
  • Android - 如何设置所有屏幕的背景颜色?

    维护字体和颜色样式的最佳实践是什么 我制作了一个 color xml 文件 用于更改按钮等单独元素的颜色 但我不确定 Android 希望开发人员如何组织他们的样式 例如 我希望所有屏幕都具有相同的背景颜色 我怎么做 我需要为每个 Acti
  • 终端 (Mac) 上的 ndk-build 命令出错

    这是我在 bashrc 中的环境变量设置 export ANDROID SDK AndroidSDK android sdks export ANDROID NDK AndroidNDK android ndk r8d export PAT
  • 使用 Delphi 10.2.1 Tokyo 的模态 Android 对话框

    我有以下用于在 Android 上显示模式消息的 Delphi 代码 该代码在 10 1 Berlin 上运行良好 但在 Delphi 10 2 1 Tokyo 上停止运行 此过程现在会挂起 Android 应用程序 procedure c
  • Android Fragment 中的 SharedPreferences

    我正在尝试读取 Fragment 内的 SharedPreferences 我的代码用于获取任何其他活动中的首选项 SharedPreferences preferences getSharedPreferences pref 0 我收到错
  • 即时应用程序上的文本转语音崩溃

    我正在实现一个即时应用程序 该应用程序利用 Android 设备上提供的文本转语音功能 我已经设法得到了TextToSpeech按照 Android 开发博客文章中详细说明的说明 实例已初始化并可在非即时应用程序中正常工作Android 中
  • 喷气背包中不同类型的宽度组成

    我正在 jetpack compose 的文本字段中工作 我想建立这样的东西 TextField value value onValueChange value it modifier Modifier requiredWidth 56 d
  • XML 文档结构必须在同一实体内开始和结束

    我是 eclipse 的新手 我刚刚开始编写一些代码 实际上只是从网站复制并粘贴 谁能帮我解决这个问题 错误出现在最后一行
  • 不幸的是应用程序已在 Android 模拟器中停止

    我是 Android 新手 正在尝试一些小应用程序 例如 Compass 当我在模拟器中运行应用程序时 它会给出消息Unfortunately Compass has Stopped 我没有编译时错误 我该如何解决这个问题 是什么原因造成的
  • 如何强制刷新 CallLog.Calls.CACHED_NAME 列?

    我的目标是从通话记录中收集所有未知的电话号码 这可以通过以下代码来实现 private static final String CALLOG PROJECTION CallLog Calls ID CallLog Calls CACHED
  • API 24 AccessibilityService.dispatchGesture() 方法如何工作?

    通过 API 24 我们有了一种向设备发送手势的方法 但是目前还没有可靠的文档或示例 我正在尝试让它工作 但目前手势每次都会点击 onCancelled 回调 这是我调用该方法的代码 TargetApi 24 private void pr
  • 如何在运行时检查授予权限?

    In Android M 预览版 用户可以选择特定的应用程序并检索特定的权限 所以我问如何在运行时检查授予权限 您可以使用以下复制的代码https android googlesource com platform frameworks b
  • 切换按钮形状不变

    我正在尝试制作一个带有绿色背景的圆形切换按钮 我用了
  • 在 Android 上提取/修改视频帧

    我有一个视频文件 我想获取视频的每一帧并对帧进行一些修改 例如在其中绘制另一个位图 放置一些文本等 Android 中是否有任何 API 框架可用于从视频中获取帧 我在 iOS 中使用他们的 AVFramework 做了类似的事情 如果可以

随机推荐