Jetpack compose snapshotFlow 未按预期工作

问题描述 投票:0回答:3

我试图帮助某人解决这个问题

snapshotFlow
然后我们都很想知道这个州问题。正如我们所知
snapshotFlow
将帮助我们获得流状态值。

问题

 val (number1, setNumber1) = remember {
        mutableStateOf(0)
    }

我们已经像上面的代码一样使用了这种状态。为了设置该值,我们使用了另一种方法。但由于某种原因,这个

snapshotFlow
不起作用,并且在
LaunchedEffect
中我们无法收集这些值。但后来尝试了这样。

 val number2 = remember {
        mutableStateOf(0)
    }

这按预期工作。 那么可能是什么问题呢。当我们更改这些值时,

number1Flow
不会收集这些值,但
number2Flow
可以工作。

我们错过了什么,请告诉我们。

还有完整的代码。

@Composable
fun Sample() {
    val (number1, setNumber1) = remember {
        mutableStateOf(0)
    }

    val number2 = remember {
        mutableStateOf(0)
    }

    LaunchedEffect(key1 = true) {
        snapshotFlow {
            number1
        }.collect {
            Log.v("number1Flow", it.toString())
        }
    }
    LaunchedEffect(key1 = true) {
        snapshotFlow {
            number2.value
        }.collect {
            Log.v("number2Flow", it.toString())
        }
    }
    Text(
        text = "number1= $number1",
    )
    Text(
        text = "number2= ${number2.value}",
    )

    Button(onClick = {
        setNumber1(number1 + 1)
        number2.value += 1
    }) {
        Text(
            text = "increase the value",
        )
    }
}
android android-jetpack-compose
3个回答
5
投票

SnapshotFlow 的工作原理与重组类似 - 它跟踪

State.value
的读取以了解何时发出。因此,要使
snapshotFlow
工作,必须在
snapshotFlow {}
块内部读取该值,这在第一种情况下不会发生。在第二种情况下,当您执行以下操作时,会在块内部读取值(这是显而易见的)

val number by remember { mutableStateOf(0) }
LaunchedEffect(Unit) { snapshotFlow { number } }

值也会在块内部读取,尽管由于委托的原因它不是直接可见的。但第一种情况与这样做是一样的:

val number = remember { mutableStateOf(0) }
val numberValue = number.value
LaunchedEffect(Unit) { snapshotFlow { numberValue } }

这里,该值是在

snapshotFlow
块之外读取的,这意味着它不知道要跟踪哪些更改。

这意味着一旦你使用解构声明来获取值和setValue,就不可能从中创建

snapshotFlow
。唯一的方法就是保留
State

val numberState = remember { mutableStateOf(0) }
val (number, setNumber) = numberState
LaunchedEffect(Unit) { snapshotFlow { numberState.value } }

1
投票

您正在使用

 创建一个新的 
Flow

val number1Flow = snapshotFlow {
    number1
}

在每次重新组合时,您收集的组合就是最初分配的组合。如果您记录

number1Flow
number2Flow
实例,您将看到在每个按钮上单击都会创建新实例。

您可以在 LaunchedEffect 中创建 Flow 并使用

收集相同的 Flow
LaunchedEffect(key1 = true) {
    snapshotFlow {
        number2.value
    }.collect {
       
    }
}

0
投票

请看一下这三个示例,其中代码块在可组合项下执行:

示例1

val x = remember { mutableStateOf("X1") }
LaunchedEffect(Unit) {
    snapshotFlow { x.value }.collect { println("x collected: $it") }
}
LaunchedEffect(Unit){
    delay(300)
    x.value = "X2"
    println("x.value: ${x.value}")
}

//Outputs:
//    x collected: X1
//    x.value: X2
//    x collected: X2

示例2

var y by remember { mutableStateOf("Y1") }
LaunchedEffect(Unit) {
    snapshotFlow { y }.collect { println("y collected: $it") }
}
LaunchedEffect(Unit) {
    delay(300)
    y = "Y2"
    println("y: $y")
}

//Outputs:
//    y collected: Y1
//    y: Y2
//    y collected: Y2

示例3

val (zValue, zSetter) = remember { mutableStateOf("Z1") }
LaunchedEffect(Unit) {
    snapshotFlow { zValue }.collect { println("zValue collected: $it") }
}
LaunchedEffect(Unit) {
    delay(300)
    zSetter("Z2")
    println("zValue: $zValue")
}

//Outputs:
//    zValue collected: Z1
//    zValue: Z1

请注意,示例 1 和 2 的行为相同,而示例 3 面临与您的问题相同的问题,其中值

zValue
未更新。


这个问题的关键是 1. MutableState

解构声明
的行为,以及 2.
snapshotFlow{ ... }
函数的行为。

  1. component1
    MutableState
    是其解构时的
    value
  2. 为了使
    SnapshotFlow
    成为
    emit
    一个新值,必须在
    value
    块内访问
    State
    snapshotFlow{ ... }
    属性。

因此,要解决该问题,只需不要使用解构声明模式即可;直接访问状态或通过委托访问状态,如示例 1 和 2 所示。

© www.soinside.com 2019 - 2024. All rights reserved.