Skip to content

Instantly share code, notes, and snippets.

@belinwu
Forked from OKatrych/VMScope.kt
Created October 25, 2023 05:19
Show Gist options
  • Save belinwu/a8df61828b85d83e2d6f6e5b480cc2d9 to your computer and use it in GitHub Desktop.
Save belinwu/a8df61828b85d83e2d6f6e5b480cc2d9 to your computer and use it in GitHub Desktop.
Scope ViewModelStoreOwner to Composable lifecycle
@Composable
internal fun ProvidesViewModelStoreOwner(
ownerKey: String = rememberSaveable { UUID.randomUUID().toString() },
ownerHolder: CompositionScopedVMStoreOwnerHolder = CompositionScopedVMStoreOwnerHolder(),
content: @Composable () -> Unit,
) {
val context = LocalContext.current
remember {
object : RememberObserver {
override fun onRemembered() = Unit
override fun onAbandoned() { clear() }
override fun onForgotten() { clear() }
private fun clear() {
val isChangingConfigurations = context.findActivity().isChangingConfigurations
if (!isChangingConfigurations) {
ownerHolder.remove(ownerKey)
}
}
}
}
val viewModelStoreOwner: ViewModelStoreOwner = remember(ownerHolder, ownerKey) {
ownerHolder.getOwner(ownerKey)
}
CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) {
content()
}
}
internal class CompositionScopedVMStoreOwnerHolder : ViewModel() {
private val lock = ReentrantLock()
private val storeOwnerMap: MutableMap<String, ViewModelStoreOwner> = mutableMapOf()
fun getOwner(key: String): ViewModelStoreOwner = lock.withLock {
storeOwnerMap.getOrPut(key) {
object : ViewModelStoreOwner {
override val viewModelStore = ViewModelStore()
}
}
}
fun remove(key: String) = lock.withLock {
storeOwnerMap[key]?.viewModelStore?.clear()
storeOwnerMap.remove(key)
}
override fun onCleared() = lock.withLock {
storeOwnerMap.forEach { it.value.viewModelStore.clear() }
storeOwnerMap.clear()
super.onCleared()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment