撰写:带有键的 Remember() 与 derivativeStateOf()

Fel*_* D. 58 kotlin android-jetpack-compose jetbrains-compose

这两种方法有什么区别?

  1. val result = remember(key1, key2) { computeIt(key1, key2) }文档
  2. val result by remember { derivedStateOf { computeIt(key1, key2) } }文档

key1如果和 都没有key2改变,则两者都避免重新计算。如果导出下游状态,第二个也可以避免重新计算,但除此之外,它们的行为是相同的,不是吗?

Ben*_*ove 62

derivedStateOf {}当您的状态或键的变化超出您想要更新 UI 的范围时使用。它充当您的缓冲区,缓冲您不需要的更改。这是键控remember {}derivedStateOf {}. 使用remember {},您仍然可以根据您的关键更改重新组合,如果您需要的话,这并不是一件坏事。如果您不需要这些重组,那就可以derivedStateOf {}了。

举个例子,仅当用户滚动 时才显示按钮LazyColumn

val isVisible = lazyListState.firstVisibleItemIndex > 0
Run Code Online (Sandbox Code Playgroud)

firstVisibleItemIndex当用户滚动时会改变 0、1、2 等,并在每次改变时导致重新组合。

我只关心它是 0 还是非 0,并且只想在条件改变时重新组合。

derivedStateOf是我的缓冲区,它缓冲所有我不需要的额外状态更改,并将重组限制为仅在更改时进行derivedStateOf

val isVisible = remember { derivedStateOf { lazyListState.firstVisibleItemIndex > 0 } }
Run Code Online (Sandbox Code Playgroud)

对于问题中给出的示例, aremember(key1, key2) {}是在那里使用的正确 API,不是derivedStateOf {}因为您希望 UI 在键更改时更新,所以没有任何更改可以缓冲。

derivedStateOf更新:本次演讲中有详细解释https://www.youtube.com/watch?v=ahXLwg2JYpc&t=948s

  • 当它正在读取的 State 发生变化时,Compose 会重新组合。如果没有衍生状态,您将读取的状态对象是lazyListState,因此任何时候它发生变化时您都将重新组合。returnedStateOf 为您创建一个新的 State 对象,该对象仅在 lls.fvii > 0 发生变化时才会发生变化,因此它的重组会少得多。 (3认同)

Nek*_*cer 29

AFAIK 这里没有区别。这只是一个巧合,两个构造在这种情况下都在做同样的事情下都在做同样的事情。但是,还是有区别的!

最大的一个是它derivedStateOf不可组合,并且它本身不缓存(remember确实)。因此derivedStateOf适用于仅在密钥更改时才必须运行的长时间运行的计算。或者它可用于合并不可组合的多个状态(例如在自定义类中)。

我认为对于“局外人”来说,确切的解释是模糊的,我们需要一些撰写团队成员的意见:)。我的上述内容的来源是slack 上的这个线程和我自己的实验

编辑:

今天我学到了另一种derivedStateOf用法,非常重要。当使用一些非常频繁使用的值进行计算时,它可以用于限制重组计数。

例子:

// we have a variable scrollState: Int that gets updated every time user scrolls
// we want to update our counter for every 100 pixels scrolled.
// To avoid recomposition every single pixel change we are using derivedStateOf
val counter = remember {
    derivedStateOf {
        (scrollState / 100).roundToInt()
    }
}

// this will be recomposed only on counter change, so it will "ignore" scrollState in 99% of cases
Text(counter.toString()).
Run Code Online (Sandbox Code Playgroud)

我的来源非常直接——来自 compose 运行时和快照系统的作者 Chuck Jazdzewski 本人。我强烈建议在这里和他一起观看直播:https://www.youtube.com/watch ?v=waJ_dklg6fU

编辑2:

我们终于有了一些官方性能文档,其中稍微提到了derivedStateOf. 所以官方的目的derivedStateOf是限制合成数量(就像我的例子一样)。

  • 谢谢@Jakoss!我还觉得文档对此的解释有点太模糊了。 (2认同)
  • 虽然我喜欢“正常工作”的组合,但一些更“内部”的东西应该更好地记录下来。但我确信 compose 会到达那里。致力于此的团队似乎非常投入 (2认同)