Skip to content

Instantly share code, notes, and snippets.

@OKatrych
Created April 17, 2023 13:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save OKatrych/66d2dba67cadfc6097cbed320f8d4253 to your computer and use it in GitHub Desktop.
Save OKatrych/66d2dba67cadfc6097cbed320f8d4253 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