我有一个关于StateFlow和用户界面重组的问题.简而言之,我的ViewModel有三个流程:

accountFlow,用于从数据库中获取当前登录的账号.

timelinePositionFlow,用于从当前登录的账号中检索最后一条浏览位置记录.

timelineFlow,它包含数据库中存储的当前登录帐户的所有帖子.

我面临的问题是,我的应用程序可以在多个账户之间切换,并浏览信息.因 for each 帐户都有一个存储的时间线位置,所以我需要使用rememberLazyListState(initialFirstVisibleItemIndex = ...)来初始化LazyColumn的位置.但是,如果我切换帐户,并且StateFlow发出新帐户的值,则rememberLazyListState不会重新组合.因此新账户的时间线大小可能只有20,而旧账户的时间线位置索引大于20,这将导致java.lang.IndexOutOfBoundsException错误 有没有解决这个问题的好办法?

视图模型

  private val activeAccountFlow = accountDao
    .getActiveAccountFlow()
    .filterNotNull()
    .distinctUntilChanged { old, new -> old.id == new.id }

  val timelinePosition = activeAccountFlow
    .mapLatest { TimelinePosition(it.firstVisibleItemIndex, it.offset) }
    .stateIn(
      scope = 视图模型Scope,
      started = SharingStarted.WhileSubscribed(),
      initialValue = TimelinePosition()
    )

  val timeline = activeAccountFlow
    .flatMapLatest { timelineDao.getStatusListWithFlow(it.id) }
    .map { splitReorderStatus(it).toUiData().toImmutableList() }
    .stateIn(
      scope = 视图模型Scope,
      started = SharingStarted.WhileSubscribed(),
      initialValue = persistentListOf()
    )

用户界面

  val timeline by 视图模型.timeline.collectAsStateWithLifecycle()
  val timelinePosition by 视图模型.timelinePosition.collectAsStateWithLifecycle()

  val lazyState = rememberLazyListState(
    initialFirstVisibleItemIndex = timelinePosition.index,
    initialFirstVisibleItemScrollOffset = timelinePosition.offset
  )

  LazyColumn { ... }

推荐答案

try 手动保存LazyListState.通过将第一个参数rememberSaveable设置为timelinePosition,当timelinePosition更改时,lazyState将重置.

    val lazyState = rememberSaveable(timelinePosition, saver = LazyListState.Saver) {
        LazyListState(timelinePosition.index, timelinePosition.offset)
    }

一百零八 如果在lazyState更改时更新timelinePosition,则此方法将不起作用,因为它将引入循环依赖.在这种情况下,我建议改变你获得timelinePosition英镑的方式.你并不真的需要StateFlow,因为当活跃用户发生变化时,你只需要阅读一次.在accountDaoViewModel上添加一次暂停方法,以获得timelinePosition,并在timeline发生变化时使用它,类似于:

    LaunchedEffect(timeline) {
        timelinePosition = viewModel.getTimeLinePosition(activeUserId)
        lazyState.animateScrollToItem(timelinePosition.index, timelinePosition.offset)
    }

Android相关问答推荐

如何在Android中使用TextView设置动态文本的样式

将Any强制转换为Integer将从API返回NullPointerException

如何使用Jetpack Compose使水平pager 显示离屏页面?

泛型类型lambda函数参数作为函数参数

LocalContext.current的问题(@Composable调用只能从@Composable函数的上下文发生)

如何使用进度条和返回函数进行API调用,同时在Android上使用Kotlin保持高效?

是否可以附加事件处理程序,如onClick,拖动到Canvas Composable中绘制的内容,或使用drawBehind修饰符?

可组合函数无限地从视图模型获取值

是什么导致调用 Firebase 服务器?

CoroutineScope 与挂起函数

在 Jetpack Compose 中使用 .observeAsState() 时,如何在更改 MutableLiveData 的值后开始执行一段代码?

Compose Accompaniist Pager 中的 TabRow/Tab 重组问题

如何在 BasicTextField 中全选焦点

java.lang.IllegalArgumentException:与请求匹配的导航目的地 NavDeepLinkRequest

无法解析依赖项'com.github.smarteist:autoimageslider:1.4.0-appcompat'

Android Jetpack Compose - 每次文本字段值更改时,可组合函数都会重新组合

JetPack Compose - 卡片行中的权重()不起作用

为什么按钮没有拉伸到屏幕边缘?

在 Jetpack Compose 中 Select 要省略的文本

如何删除 Ktor 客户端 2.0.0 的默认标头