Jetpack 撰写列表在重新排序或过滤后选择了错误的项目

Jetpack compose list wrong item selected after reordering or filtering

我有一个 ViewModel 可以生成这样的 StateFlow:

private val _profiles = MutableStateFlow<List<ProfileSnap>>(listOf())
val profiles: StateFlow<List<ProfileSnap>>
  get() = _profiles

值在另一个乐趣中更新:

private fun loadProfiles() = viewModelScope.launch {
   _profiles.value = profileDao.getAll(profilesSearch, profilesSort)
}

最后,在 Compose 中我列出了所有值(这是我的代码的简化版本):

@Composable
fun SetContent(viewModel: ProfilesViewModel){
   val profiles = viewModel.profiles.collectAsState()
   LazyColumn(
      modifier = Modifier
         .fillMaxHeight()
   ) {
      itemsIndexed(items = profiles.value) { _, profile ->
         Text(
            text = "(${profile.profileId}) ${profile.label}",
            modifier = Modifier
            .pointerInput(Unit) {
               detectTapGestures(
                  onLongPress = {
                     Log.d(TAG, "onLongPress: ${profile.profileId}")
                  },
                  onTap = {
                     Log.d(TAG, "onTap: ${profile.profileId}")
                  },
               )
            }   
         ) 
      }
   }    
}

一开始,当我到达列表片段并单击一个元素时,我得到了正确的对应 profileId。但是,当我应用过滤器或更改列表排序并调用 loadProfiles() 函数时:

  1. 列表根据新筛选的 and/sorted 配置文件正确更改
  2. 当我点击一个元素时,我得到了错误的 profileId,我似乎是以前的列表配置之一!

我做错了什么?配置文件不是最新的?但是,如果它们没有更新,为什么列表“在图形上”是正确的?这里发生了什么:

(1) A
-----
(2) B   
-----
(3) C   <== CLICK - onTap: 3 / LONGPRESS - onLongPress: 3

更改排序顺序:

(3) C
-----
(2) B   
-----
(1) A   <== CLICK - onTap: 3 [should has been 1] / LONGPRESS - onLongPress: 3 [should has been 1]

非常感谢

您可以查看 official doc:

By default, each item's state is keyed against the position of the item in the list. However, this can cause issues if the data set changes, since items which change position effectively lose any remembered state. If you imagine the scenario of LazyRow within a LazyColumn, if the row changes item position, the user would then lose their scroll position within the row.

To combat this, you can provide a stable and unique key for each item, providing a block to the key parameter. Providing a stable key enables item state to be consistent across data-set changes:

LazyColumn() {
      items(
            items = profiles.value,
            key = { profile ->
                    // Return a stable + unique key for the item
                    profile.profileId
                }
      ) { profile ->
         //....
      }
   } 

根据 Gabriele 的提示,这是一个可用的版本(我找不到相同的项目功能签名):

LazyColumn() {
    items(
      count = profiles.value.size,
      key = { index -> profiles.value[index].profileId }
    ) { index ->
      val profile = profiles.value[index]
      Item(profile)
      Line()
    }
  }