android 是否只监听List类型的StateFlow中特定对象的更改?

vsnjm48y  于 2023-06-04  发布在  Android
关注(0)|答案(4)|浏览(298)

如何只监听MutableStateFlow类型列表中的特定元素?如果我们监听整个列表,那么所有正在监听列表的视图如果被改变,将重建它们自己,这是我不希望的。

class ArticleViewModel: ViewModel() {

val articles = MutableStateFlow<List<Article>>( /* articles list */)

}

@Composable
fun ArticlePreview (index: Int) {
    

   val model: ArticleViewModel: viewModel();
  
 // Problem: Since it is listening to entire list. If the list changes, the entire ArticlePreview widgets will rebuild but I only want to change a particular item if some property of the current item changes in the list.

   val previews by model.articles.collectAsState(); 
  
   val currentPreview = previews[index];

    Text(text = currentPreview.body);
  
}
6yjfywim

6yjfywim1#

Compose通常足够聪明,可以自己解决这个问题:它“知道”旧列表,“知道”新列表,因此它“知道”差异。然后,它应该只重组差异。
但是,这需要使用equals函数。最简单的方法是确保您的Articledata class
如果改变了,观点会重新建立自己,这是我不想要的。
虽然不希望过多地重建ui,但您必须习惯于不时地编写重建ui

g2ieeal7

g2ieeal72#

您可以在compose函数中使用derivedStateOf,如下所示:

val currentPreview = remember {
    derivedStateOf {
       previews[index]
    }
}

Text(text = currentPreview.value)

derivedStateOf函数仅在特定数据发生更改时触发更新,从而有效地管理用户界面的重组。此优化可以通过减少整个屏幕的不必要重绘次数来显著提高应用性能。

628mspwn

628mspwn3#

如果你不想监听整个列表,那么你应该有另一个mutableStateFlow,它只包含一个Article。你应该有一个函数将索引传递给viewModel,并触发新的mutableStateFlow。所以你的整个widget不会更新。

class ArticleViewModel: ViewModel() {

    val articles = MutableStateFlow<List<Article>>( /* articles list */)

    private val _article = MutableStateFlow<Article>()
    val article = _article.asStateFlow()

    fun selectedArticle(index: String) {
        _article.value = articles[index]
    }

}

selectedArticle函数将触发article状态流,您可以从组合工具中收集该状态流。如果你的列表改变了,你的小部件组合也不会更新。

but5z9lq

but5z9lq4#

要更改流量数据,可以使用map
它返回一个流,为了在composable中具有非可选值,您可以使用stateIn从它构建状态流
为了使代码更简洁,我使用了以下扩展-它将相同的transform应用于初始值和Map值:

fun <T, R> StateFlow<T>.mapState(
    scope: CoroutineScope,
    transform: (value: T) -> R,
): StateFlow<R> =
    map(transform)
        .stateIn(
            scope,
            SharingStarted.Eagerly,
            transform(value)
        )

然后你可以很容易地在composable中使用它:

val coroutineScope = rememberCoroutineScope()

val article by remember(index) {
    viewModel.articles
        .mapState(coroutineScope) {
            it[index]
        }
}.collectAsState()

在这种情况下,StateFlow生命周期将绑定到Composable。请注意,mapState应该在remember内部调用,以防止重新组合时的额外工作。
通常你可以在视图模型中使用相同的技术-但是如果你的map依赖于index参数,那么在视图级别上更容易。

相关问题