Android Jetpack Compose中derivedStateOf{}与remember{} with keys的区别

图片
derivedStateOf{} VS remember{}

在这篇短文中,我将清楚地解释derivedStateOf{}和使用带有keys的remember{}之间的区别。阅读完本文后,你将对它们之间的区别有非常清晰的认识。

先决条件

为了理解本文,你必须熟悉以下概念:

  • • 在Compose中创建和记住状态
  • • 状态与重新组合的关系
  • • 重新组合

带有keys的remember{}

remember{}函数用于在组合中记住状态。这有助于可组合函数在重新组合时记住先前的值。remember函数还可以带有一些参数,称为“keys”。键可以是任何随时间而变化的值。该函数可以将多个键作为参数。在Compose中,我们使用状态来表示可以随时间改变的值。当传递给remember块的任何一个键的值发生更改时,remember块的尾随lambda将被重新执行。如果需要记住状态并仅在另一个状态更改时重新计算,则这非常方便。 例如,假设您想在用户更改筛选器时过滤列表。您可以创建一个使用当前选定的筛选器作为键的remember块。仅当当前选定的筛选器更改时,过滤列表才会重新计算。

val filteredTasksByName by remember(currentlySelectedFilter) {
    tasks.filter{ it.name == currentlySelectedFilter.filterName }
}

derivedStateOf

尽管乍一看,derivedStateOf 可能看起来像是 remember 的升级版,但它主要用于执行另一个重要功能。虽然 derivedStateOf 的尾随 lambda 表达式在引用的任何状态值发生更改时都会重新计算,但这消除了显式指定键的需要。

@Composable
fun someComposableFunction(){
.
.
.
    var stateVariable by remember {
        derivedStateOf {
            // any state that is read within this block will cause 
            // this block to be re-executed when that state changes value.
        }
    }
.
.
.
}

如前所述,它用于执行另一个重要功能——减少不必要的重新组合。在记住的情况下,即使已更改的键设置为先前设置的相同值,lambda也会重新计算。我将使用我在另一篇文章中使用的示例,其中详细介绍了derivedStateOf。如果您想了解有关derivedStateOf是什么以及应在何时使用它的详细指南,请查看该文章。假设我们想在用户滚动过惰性列表中的第3个项目时显示“滚动到顶部”FAB(浮动操作按钮)。如果我们使用remember {},可能会像这样做。

@Composable
fun someComposableFunction(){
    .
    .
    var isScrollUpFabVisible = remember(lazyListState.firstVisibleItemIndex){
       lazyListState.firstVisibleItemIndex > 3 
     }
      .
      .
      if(IsScrollUpFabVisible){
          /* Display the floating action button*/
      }
      .
      .
}

这个实现虽然可以工作,但是会导致很多不必要的重新组合。lazyListState.firstVisibleItemIndex 属性会非常频繁地变化。这很有道理,因为当用户滚动列表时,第一个可见项的索引会随之变化。这会导致可组合的函数在用户持续滚动时重新组合!如果我们把状态变化看作一系列数据流,那么就会得到类似于这样的数据流——false、false、false、false、true、true、true……等等。将状态从 true 到 false 和相反的方向上移动时重新组合会更好,这正是 derivedStateOf 所做的。它查看新值并将其与旧值进行比较。如果两者相同,则不会更改状态的值。由于状态的值没有改变,读取该状态的可组合函数也不会重新组合。因此,减少了不必要的重新组合。这是 derivedStateOf 的主要功能,应该在使用状态的可组合函数需要比状态更改频率低时使用。可以使用下面的代码更有效地实现相同的功能:

@Composable
fun someComposableFunction(){
  .
  .
  var isScrollUpFabVisible by remember {
        derivedStateOf { lazyListState.firstVisibleItemIndex > 3}
    }
  .
  .
  if(IsScrollUpFabVisible){
     /* Display the floating action button*/
  }
  .
  .
}

结论

本文介绍了 derivedStateOf 和带有键值的 remember 之间的区别。虽然它们都可以实现相似的功能,但 derivedStateOf 主要用于减少不必要的重组,而 remember 则用于记忆状态。当状态更改的速率高于组合函数的重组速率时,应该使用 derivedStateOf。记住,remember 是一个组合函数,而 derivedStateOf 是一个普通的 Kotlin 函数。希望你能够理解这两个函数之间的区别,并在编程中灵活使用它们。


欢迎关注我的公众号“虎哥Lovedroid”,原创技术文章第一时间推送。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/28855.html

联系我们
联系我们
分享本页
返回顶部