Make `snapshotFlow` no longer experimental
Also removes experimental from `withMutableSnapshot` and
moves it to as a companion method of Snapshot.
Fixes: 178392296, 178490402
Test: ./gradlew :compose:r:r:tDUT
Relnote: """`snapshotFlow` and `withMutableSnapshot` are no longer
experimental"""
Change-Id: I6a45fac62267a318481e9a3ba8a3acf3162219f6
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 833d1e5..dbb5c5b 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -692,6 +692,7 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> registerApplyObserver(kotlin.jvm.functions.Function2<? super java.util.Set<?>,? super androidx.compose.runtime.snapshots.Snapshot,kotlin.Unit> observer);
method public kotlin.jvm.functions.Function0<kotlin.Unit> registerGlobalWriteObserver(kotlin.jvm.functions.Function1<java.lang.Object,kotlin.Unit> observer);
method public void sendApplyNotifications();
+ method public inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
property public final androidx.compose.runtime.snapshots.Snapshot! current;
}
@@ -724,8 +725,8 @@
}
public final class SnapshotFlowKt {
- method @androidx.compose.runtime.ExperimentalComposeApi public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
- method @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
+ method public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
+ method @Deprecated @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
}
public final class SnapshotIdSetKt {
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index 833d1e5..dbb5c5b 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -692,6 +692,7 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> registerApplyObserver(kotlin.jvm.functions.Function2<? super java.util.Set<?>,? super androidx.compose.runtime.snapshots.Snapshot,kotlin.Unit> observer);
method public kotlin.jvm.functions.Function0<kotlin.Unit> registerGlobalWriteObserver(kotlin.jvm.functions.Function1<java.lang.Object,kotlin.Unit> observer);
method public void sendApplyNotifications();
+ method public inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
property public final androidx.compose.runtime.snapshots.Snapshot! current;
}
@@ -724,8 +725,8 @@
}
public final class SnapshotFlowKt {
- method @androidx.compose.runtime.ExperimentalComposeApi public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
- method @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
+ method public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
+ method @Deprecated @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
}
public final class SnapshotIdSetKt {
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 07e1499..9e431c7 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -723,6 +723,7 @@
method @kotlin.PublishedApi internal androidx.compose.runtime.snapshots.Snapshot? removeCurrent();
method @kotlin.PublishedApi internal void restoreCurrent(androidx.compose.runtime.snapshots.Snapshot? previous);
method public void sendApplyNotifications();
+ method public inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
property public final androidx.compose.runtime.snapshots.Snapshot! current;
}
@@ -755,8 +756,8 @@
}
public final class SnapshotFlowKt {
- method @androidx.compose.runtime.ExperimentalComposeApi public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
- method @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
+ method public static <T> kotlinx.coroutines.flow.Flow<T> snapshotFlow(kotlin.jvm.functions.Function0<? extends T> block);
+ method @Deprecated @androidx.compose.runtime.ExperimentalComposeApi public static inline <R> R! withMutableSnapshot(kotlin.jvm.functions.Function0<? extends R> block);
}
public final class SnapshotIdSetKt {
diff --git a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotSamples.kt
index 1e62c6d..2bf9ecf 100644
--- a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotSamples.kt
+++ b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotSamples.kt
@@ -21,8 +21,8 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.snapshotFlow
-import androidx.compose.runtime.snapshots.withMutableSnapshot
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@@ -54,7 +54,7 @@
// ...
// Change snapshot state; greetPersonFlow will emit a new greeting
- withMutableSnapshot {
+ Snapshot.withMutableSnapshot {
greeting = "Ahoy"
person = "Sean"
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 8deda49..0e904d0 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -317,6 +317,31 @@
}
/**
+ * Take a [MutableSnapshot] and run [block] within it. When [block] returns successfully,
+ * attempt to [MutableSnapshot.apply] the snapshot. Returns the result of [block] or throws
+ * [SnapshotApplyConflictException] if snapshot changes attempted by [block] could not be
+ * applied.
+ *
+ * Prior to returning, any changes made to snapshot state (e.g. state holders returned by
+ * [androidx.compose.runtime.mutableStateOf] are not visible to other threads. When
+ * [withMutableSnapshot] returns successfully those changes will be made visible to other
+ * threads and any snapshot observers (e.g. [snapshotFlow]) will be notified of changes.
+ *
+ * [block] must not suspend if [withMutableSnapshot] is called from a suspend function.
+ */
+ // TODO: determine a good way to prevent/discourage suspending in an inlined [block]
+ inline fun <R> withMutableSnapshot(
+ block: () -> R
+ ): R = takeMutableSnapshot().run {
+ try {
+ enter(block).also { apply().check() }
+ } catch (t: Throwable) {
+ dispose()
+ throw t
+ }
+ }
+
+ /**
* Observe reads and or write of state objects in the current thread.
*
* This only affects the current snapshot (if any) and any new snapshots create from
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotFlow.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotFlow.kt
index 3ecb3ee..e2a2a8cd 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotFlow.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotFlow.kt
@@ -60,7 +60,6 @@
* intermediate states as well as run multiple times for the same state and the result should
* be the same.
*/
-@ExperimentalComposeApi
fun <T> snapshotFlow(
block: () -> T
): Flow<T> = flow {
@@ -140,6 +139,12 @@
*/
// TODO: determine a good way to prevent/discourage suspending in an inlined [block]
@ExperimentalComposeApi
+@Deprecated(
+ "Use Snapshot.withMutableSnapshot() instead",
+ ReplaceWith(
+ "Snapshot.withMutableSnapshot(block)"
+ )
+)
inline fun <R> withMutableSnapshot(
block: () -> R
): R = takeMutableSnapshot().run {
@@ -149,4 +154,4 @@
dispose()
throw t
}
-}
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotFlowTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotFlowTests.kt
index 2bd56c8..5c9a611 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotFlowTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotFlowTests.kt
@@ -45,7 +45,7 @@
assertEquals(2, result, "value after initial run")
- withMutableSnapshot {
+ Snapshot.withMutableSnapshot {
state = 5
}
@@ -69,13 +69,13 @@
yield()
assertEquals(1, runCount, "snapshot collector initial run")
- withMutableSnapshot { state++ }
+ Snapshot.withMutableSnapshot { state++ }
yield()
assertEquals(2, runCount, "made one change")
- withMutableSnapshot { state++ }
- withMutableSnapshot { state++ }
+ Snapshot.withMutableSnapshot { state++ }
+ Snapshot.withMutableSnapshot { state++ }
yield()
assertEquals(3, runCount, "coalesced two changes")
@@ -98,7 +98,7 @@
assertEquals(1, runCount, "initial run")
- withMutableSnapshot { unrelatedState++ }
+ Snapshot.withMutableSnapshot { unrelatedState++ }
yield()
assertEquals(1, runCount, "after changing unrelated state")
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
index eaeebde..d2fed78 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
@@ -21,7 +21,7 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.withMutableSnapshot
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.InspectableValue
@@ -264,7 +264,7 @@
}
}
scenario.moveToState(Lifecycle.State.STARTED)
- withMutableSnapshot {
+ Snapshot.withMutableSnapshot {
toAdd = "secondary"
}
assertTrue("waiting for relaunch timed out", latch.await(1, TimeUnit.SECONDS))