Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ class ViewStore<S : State, A : Action, E : Event> internal constructor(
* For a given remembered Store instance, this function returns the same [ViewStore] instance across
* recompositions. A new [ViewStore] is created only when a new Store instance is remembered for
* [key].
* The [autoClose] value is fixed when that remembered Store instance is adopted. Recomposition
* alone does not change close ownership for the same Store, but when [key] causes a different
* Store instance to be remembered, the current [autoClose] value is used for that new Store.
*
* @param key Key used to remember and retain the Store instance
* @param autoClose Whether to close the Store when the composable leaves the composition
Expand All @@ -130,20 +133,19 @@ class ViewStore<S : State, A : Action, E : Event> internal constructor(
@Suppress("unused")
@Composable
fun <S : State, A : Action, E : Event> rememberViewStore(key: Any? = null, autoClose: Boolean = false, store: @Composable () -> Store<S, A, E>): ViewStore<S, A, E> {
val fixedAutoClose = remember { autoClose }

val holder = remember(key) {
object {
var value: Store<S, A, E>? = null
}
}
val rememberedStore = holder.value ?: store().also { holder.value = it }
val closeStoreOnDispose = remember(rememberedStore) { autoClose }

val state = rememberedStore.state.collectAsState()

DisposableEffect(rememberedStore) {
onDispose {
if (fixedAutoClose) {
if (closeStoreOnDispose) {
rememberedStore.close()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class ViewStoreJvmTest {
}

@Test
fun rememberViewStore_closeBehaviorUsesInitialAutoCloseValue() = runTest(testDispatcher) {
fun rememberViewStore_closeBehaviorIsFixedPerRememberedStore() = runTest(testDispatcher) {
val neverCloseStore = TestStore(UiState.Ready(0))
var autoClose = mutableStateOf(false)

Expand All @@ -349,14 +349,67 @@ class ViewStoreJvmTest {

assertEquals(0, neverCloseStore.closeCount)

val closeStore = TestStore(UiState.Ready(0))
val alwaysCloseStore = TestStore(UiState.Ready(0))
autoClose.value = true
withComposition(
content = {
rememberViewStore(autoClose = true) { closeStore }
rememberViewStore(autoClose = autoClose.value) { alwaysCloseStore }
},
afterSetContent = {
autoClose.value = false
},
)

assertEquals(1, closeStore.closeCount)
assertEquals(1, alwaysCloseStore.closeCount)
}

@Test
fun rememberViewStore_keyChangeAppliesAutoCloseToNewRememberedStore() = runTest(testDispatcher) {
val firstStore = TestStore(UiState.Ready(0))
val secondStore = TestStore(UiState.Ready(0))
val frameClock = BroadcastFrameClock()
var frameTimeNanos = 0L
var key = "first"
var autoClose = false

suspend fun pumpFrame() {
testScheduler.runCurrent()
frameTimeNanos += 16_000_000L
frameClock.sendFrame(frameTimeNanos)
testScheduler.runCurrent()
}

withContext(frameClock) {
withRunningRecomposer { recomposer ->
val composition = Composition(NoOpApplier(), recomposer)
try {
composition.setContent {
rememberViewStore(key = key, autoClose = autoClose) {
if (key == "first") firstStore else secondStore
}
}
repeat(2) { pumpFrame() }

autoClose = true
key = "second"
composition.setContent {
rememberViewStore(key = key, autoClose = autoClose) {
if (key == "first") firstStore else secondStore
}
}
repeat(2) { pumpFrame() }

assertEquals(0, firstStore.closeCount)
assertEquals(0, secondStore.closeCount)
} finally {
composition.dispose()
pumpFrame()
}
}
}

assertEquals(0, firstStore.closeCount)
assertEquals(1, secondStore.closeCount)
}

@Test
Expand Down
Loading