commonMain.androidx.compose.foundation.lazy.layout.LazySaveableStateHolder.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of foundation-desktop Show documentation
Show all versions of foundation-desktop Show documentation
Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.foundation.lazy.layout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
import androidx.compose.runtime.saveable.SaveableStateHolder
import androidx.compose.runtime.saveable.SaveableStateRegistry
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import androidx.compose.runtime.setValue
/**
* Provides [SaveableStateHolder] to be used with the lazy layout items.
* This allows to save the state of the items like inner LazyRow scroll position which such
* items are scrolled away in order to restore it when this item is visible again.
* However on top of the default logic provided via [rememberSaveableStateHolder] this instance
* will only save the items which are currently visible when the parent [SaveableStateRegistry]
* triggers [SaveableStateRegistry.performSave] in order to save on the space we use in the
* Android`s Bundle to not cause crash with TransactionTooLargeException.
*/
@Composable
internal fun LazySaveableStateHolderProvider(content: @Composable (SaveableStateHolder) -> Unit) {
val currentRegistry = LocalSaveableStateRegistry.current
val holder = rememberSaveable(
currentRegistry, saver = LazySaveableStateHolder.saver(currentRegistry)
) {
LazySaveableStateHolder(currentRegistry, emptyMap())
}
CompositionLocalProvider(LocalSaveableStateRegistry provides holder) {
holder.wrappedHolder = rememberSaveableStateHolder()
content(holder)
}
}
private class LazySaveableStateHolder(
private val wrappedRegistry: SaveableStateRegistry
) : SaveableStateRegistry by wrappedRegistry, SaveableStateHolder {
constructor(
parentRegistry: SaveableStateRegistry?,
restoredValues: Map>?
) : this(
SaveableStateRegistry(restoredValues) {
parentRegistry?.canBeSaved(it) ?: true
}
)
var wrappedHolder by mutableStateOf(null)
private val previouslyComposedKeys = mutableSetOf()
override fun performSave(): Map> {
val holder = wrappedHolder
if (holder != null) {
previouslyComposedKeys.forEach {
holder.removeState(it)
}
}
return wrappedRegistry.performSave()
}
@Composable
override fun SaveableStateProvider(key: Any, content: @Composable () -> Unit) {
requireNotNull(wrappedHolder).SaveableStateProvider(key, content)
DisposableEffect(key) {
previouslyComposedKeys -= key
onDispose {
previouslyComposedKeys += key
}
}
}
override fun removeState(key: Any) {
requireNotNull(wrappedHolder).removeState(key)
}
companion object {
fun saver(parentRegistry: SaveableStateRegistry?) =
Saver>>(save = {
it.performSave().ifEmpty { null }
}, restore = { restored ->
LazySaveableStateHolder(parentRegistry, restored)
})
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy