Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save belinwu/3d93f1824f9f59700a45de6b9e65eaab to your computer and use it in GitHub Desktop.

Select an option

Save belinwu/3d93f1824f9f59700a45de6b9e65eaab to your computer and use it in GitHub Desktop.

Revisions

  1. @joost-klitsie joost-klitsie revised this gist Sep 25, 2024. 2 changed files with 171 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,7 @@ fun rememberViewModelStoreOwner(
    val viewModelStoreOwnerViewModel = viewModel<ViewModelStoreOwnerViewModel> {
    ViewModelStoreOwnerViewModel()
    }
    val viewModelStore = viewModelStoreOwnerViewModel.get(viewModelKey, key, localLifecycle)
    val viewModelStoreOwner = viewModelStoreOwnerViewModel.get(viewModelKey, key, localLifecycle)

    remember {
    object : RememberObserver {
    @@ -32,7 +32,7 @@ fun rememberViewModelStoreOwner(
    }
    }
    }
    return viewModelStore
    return viewModelStoreOwner
    }

    @Composable
    @@ -88,7 +88,7 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {
    initialLifecycle: Lifecycle,
    ) {

    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    val viewModelStoreOwner: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    @@ -133,13 +133,13 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {

    fun clear() {
    supervisorJob.cancelChildren()
    viewModelStore.viewModelStore.clear()
    viewModelStoreOwner.viewModelStore.clear()
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
    this.key = key
    viewModelStore.viewModelStore.clear()
    viewModelStoreOwner.viewModelStore.clear()
    }
    attachedLifecycle.update { lifecycle }
    }
    166 changes: 166 additions & 0 deletions RememberViewModelStoreOwnerHilt.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,166 @@
    import androidx.compose.runtime.*
    import androidx.lifecycle.*
    import androidx.lifecycle.compose.LocalLifecycleOwner
    import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
    import androidx.lifecycle.viewmodel.compose.viewModel
    import kotlinx.coroutines.*
    import kotlinx.coroutines.flow.*

    @Composable
    fun rememberViewModelStoreOwner(
    key: Any?,
    ): ViewModelStoreOwner {
    val viewModelKey = "rememberViewModelStoreOwner#" + currentCompositeKeyHash.toString(36)
    val localLifecycle = LocalLifecycleOwner.current.lifecycle
    val currentViewModelStoreOwner = LocalViewModelStoreOwner.current
    val viewModelStoreOwnerViewModel = viewModel<ViewModelStoreOwnerViewModel> {
    ViewModelStoreOwnerViewModel()
    }
    val viewModelStoreOwner = viewModelStoreOwnerViewModel.get(viewModelKey, key, localLifecycle)

    remember {
    object : RememberObserver {
    override fun onAbandoned() {
    viewModelStoreOwnerViewModel.detachComposable(viewModelKey)
    }

    override fun onForgotten() {
    viewModelStoreOwnerViewModel.detachComposable(viewModelKey)
    }

    override fun onRemembered() {
    viewModelStoreOwnerViewModel.attachComposable(viewModelKey)
    }
    }
    }
    return remember(currentViewModelStoreOwner, viewModelStoreOwner) {
    if (currentViewModelStoreOwner is HasDefaultViewModelProviderFactory) {
    object : ViewModelStoreOwner by viewModelStoreOwner,
    HasDefaultViewModelProviderFactory by currentViewModelStoreOwner {}
    } else {
    viewModelStoreOwner
    }
    }
    }

    @Composable
    fun WithViewModelStoreOwner(
    key: Any?,
    content: @Composable () -> Unit,
    ) {
    CompositionLocalProvider(
    value = LocalViewModelStoreOwner provides rememberViewModelStoreOwner(key),
    content = content,
    )
    }

    @Stable
    private class ViewModelStoreOwnerViewModel : ViewModel() {

    private var attachedComposables = mapOf<String, AttachedComposable>()

    fun get(hashKey: String, key: Any?, lifecycle: Lifecycle) = attachedComposables[hashKey]?.let {
    it.update(key, lifecycle)
    it.viewModelStoreOwner
    } ?: run {
    val attachedComposable = AttachedComposable(hashKey, key, lifecycle)
    attachedComposables += hashKey to attachedComposable
    attachedComposable.viewModelStoreOwner
    }

    fun attachComposable(hashKey: String) {
    attachedComposables[hashKey]?.attachComposable()
    }

    fun detachComposable(hashKey: String) {
    attachedComposables[hashKey]?.detachComposable()
    }

    override fun onCleared() {
    attachedComposables.keys.forEach {
    dispose(it)
    }
    super.onCleared()
    }

    private fun dispose(hashKey: String) {
    attachedComposables[hashKey]?.let {
    it.clear()
    attachedComposables -= hashKey
    }
    }

    private inner class AttachedComposable(
    private val hashKey: String,
    private var key: Any?,
    initialLifecycle: Lifecycle,
    ) {

    val viewModelStoreOwner: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    private val supervisorJob: CompletableJob = SupervisorJob()
    private val scope: CoroutineScope = viewModelScope + supervisorJob
    private val attachedLifecycle = MutableStateFlow<Lifecycle?>(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()

    init {
    scope.launch {
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    .collectLatest {
    if (it == Lifecycle.Event.ON_DESTROY) {
    attachedLifecycle.update { null }
    }
    }
    }
    scope.launch {
    isAttachedToComposable.collectLatest { isAttached ->
    when {
    // If we are attached or we are destroyed, we do not need to do anything
    isAttached || attachedLifecycle.value == null -> return@collectLatest
    // If we are detached and the lifecycle state is resumed, we should reset the view model store
    attachedLifecycle.value?.currentState == Lifecycle.State.RESUMED -> {
    dispose(hashKey)
    }

    else -> {
    // We wait for the lifecycle event ON_RESUME to be triggered before resetting the ViewModelStore
    // If in the mean time we are attached again, this work is cancelled
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    // Wait for first event that matches ON_RESUME.
    .firstOrNull { it == Lifecycle.Event.ON_RESUME }
    ?: return@collectLatest
    dispose(hashKey)
    }
    }
    }
    }
    }

    fun clear() {
    supervisorJob.cancelChildren()
    viewModelStoreOwner.viewModelStore.clear()
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
    this.key = key
    viewModelStoreOwner.viewModelStore.clear()
    }
    attachedLifecycle.update { lifecycle }
    }

    fun attachComposable() {
    scope.launch { isAttachedToComposable.emit(true) }
    }

    fun detachComposable() {
    scope.launch { isAttachedToComposable.emit(false) }
    }

    }

    }
  2. @joost-klitsie joost-klitsie revised this gist Aug 29, 2024. 1 changed file with 8 additions and 4 deletions.
    12 changes: 8 additions & 4 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -77,8 +77,7 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {

    private fun dispose(hashKey: String) {
    attachedComposables[hashKey]?.let {
    it.viewModelStore.viewModelStore.clear()
    it.supervisorJob.cancelChildren()
    it.clear()
    attachedComposables -= hashKey
    }
    }
    @@ -89,11 +88,11 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {
    initialLifecycle: Lifecycle,
    ) {

    val supervisorJob: CompletableJob = SupervisorJob()
    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }


    private val supervisorJob: CompletableJob = SupervisorJob()
    private val scope: CoroutineScope = viewModelScope + supervisorJob
    private val attachedLifecycle = MutableStateFlow<Lifecycle?>(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()
    @@ -131,6 +130,11 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {
    }
    }
    }

    fun clear() {
    supervisorJob.cancelChildren()
    viewModelStore.viewModelStore.clear()
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
  3. @joost-klitsie joost-klitsie revised this gist Aug 28, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -141,11 +141,11 @@ private class ViewModelStoreOwnerViewModel : ViewModel() {
    }

    fun attachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(true) }
    scope.launch { isAttachedToComposable.emit(true) }
    }

    fun detachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(false) }
    scope.launch { isAttachedToComposable.emit(false) }
    }

    }
  4. @joost-klitsie joost-klitsie revised this gist Aug 28, 2024. 2 changed files with 153 additions and 111 deletions.
    153 changes: 153 additions & 0 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,153 @@
    import androidx.compose.runtime.*
    import androidx.compose.ui.platform.LocalLifecycleOwner
    import androidx.lifecycle.*
    import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
    import androidx.lifecycle.viewmodel.compose.viewModel
    import kotlinx.coroutines.*
    import kotlinx.coroutines.flow.*

    @Composable
    fun rememberViewModelStoreOwner(
    key: Any?,
    ): ViewModelStoreOwner {
    val viewModelKey = "rememberViewModelStoreOwner#" + currentCompositeKeyHash.toString(36)
    val localLifecycle = LocalLifecycleOwner.current.lifecycle
    val viewModelStoreOwnerViewModel = viewModel<ViewModelStoreOwnerViewModel> {
    ViewModelStoreOwnerViewModel()
    }
    val viewModelStore = viewModelStoreOwnerViewModel.get(viewModelKey, key, localLifecycle)

    remember {
    object : RememberObserver {
    override fun onAbandoned() {
    viewModelStoreOwnerViewModel.detachComposable(viewModelKey)
    }

    override fun onForgotten() {
    viewModelStoreOwnerViewModel.detachComposable(viewModelKey)
    }

    override fun onRemembered() {
    viewModelStoreOwnerViewModel.attachComposable(viewModelKey)
    }
    }
    }
    return viewModelStore
    }

    @Composable
    fun WithViewModelStoreOwner(
    key: Any?,
    content: @Composable () -> Unit,
    ) {
    CompositionLocalProvider(
    value = LocalViewModelStoreOwner provides rememberViewModelStoreOwner(key),
    content = content,
    )
    }

    @Stable
    private class ViewModelStoreOwnerViewModel : ViewModel() {

    private var attachedComposables = mapOf<String, AttachedComposable>()

    fun get(hashKey: String, key: Any?, lifecycle: Lifecycle) = attachedComposables[hashKey]?.let {
    it.update(key, lifecycle)
    it.viewModelStore
    } ?: run {
    val attachedComposable = AttachedComposable(hashKey, key, lifecycle)
    attachedComposables += hashKey to attachedComposable
    attachedComposable.viewModelStore
    }

    fun attachComposable(hashKey: String) {
    attachedComposables[hashKey]?.attachComposable()
    }

    fun detachComposable(hashKey: String) {
    attachedComposables[hashKey]?.detachComposable()
    }

    override fun onCleared() {
    attachedComposables.keys.forEach {
    dispose(it)
    }
    super.onCleared()
    }

    private fun dispose(hashKey: String) {
    attachedComposables[hashKey]?.let {
    it.viewModelStore.viewModelStore.clear()
    it.supervisorJob.cancelChildren()
    attachedComposables -= hashKey
    }
    }

    private inner class AttachedComposable(
    private val hashKey: String,
    private var key: Any?,
    initialLifecycle: Lifecycle,
    ) {

    val supervisorJob: CompletableJob = SupervisorJob()
    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    private val scope: CoroutineScope = viewModelScope + supervisorJob
    private val attachedLifecycle = MutableStateFlow<Lifecycle?>(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()

    init {
    scope.launch {
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    .collectLatest {
    if (it == Lifecycle.Event.ON_DESTROY) {
    attachedLifecycle.update { null }
    }
    }
    }
    scope.launch {
    isAttachedToComposable.collectLatest { isAttached ->
    when {
    // If we are attached or we are destroyed, we do not need to do anything
    isAttached || attachedLifecycle.value == null -> return@collectLatest
    // If we are detached and the lifecycle state is resumed, we should reset the view model store
    attachedLifecycle.value?.currentState == Lifecycle.State.RESUMED -> {
    dispose(hashKey)
    }

    else -> {
    // We wait for the lifecycle event ON_RESUME to be triggered before resetting the ViewModelStore
    // If in the mean time we are attached again, this work is cancelled
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    // Wait for first event that matches ON_RESUME.
    .firstOrNull { it == Lifecycle.Event.ON_RESUME } ?: return@collectLatest
    dispose(hashKey)
    }
    }
    }
    }
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
    this.key = key
    viewModelStore.viewModelStore.clear()
    }
    attachedLifecycle.update { lifecycle }
    }

    fun attachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(true) }
    }

    fun detachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(false) }
    }

    }

    }
    111 changes: 0 additions & 111 deletions RememberViewModelStoreOwnerOld.kt
    Original file line number Diff line number Diff line change
    @@ -1,111 +0,0 @@
    import androidx.compose.runtime.*
    import androidx.compose.ui.platform.LocalLifecycleOwner
    import androidx.lifecycle.*
    import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
    import androidx.lifecycle.viewmodel.compose.viewModel
    import kotlinx.coroutines.flow.*
    import kotlinx.coroutines.launch

    @Composable
    fun rememberViewModelStoreOwner(
    key: Any?,
    ): ViewModelStoreOwner {
    val viewModelKey = "rememberViewModelStoreOwner#" + currentCompositeKeyHash.toString(36)
    val localLifecycle = LocalLifecycleOwner.current.lifecycle
    val viewModelStoreOwnerViewModel = viewModel<ViewModelStoreOwnerViewModel>(key = viewModelKey) {
    ViewModelStoreOwnerViewModel(key, localLifecycle)
    }
    viewModelStoreOwnerViewModel.update(key, localLifecycle)

    DisposableEffect(Unit) {
    viewModelStoreOwnerViewModel.attachComposable()
    onDispose {
    viewModelStoreOwnerViewModel.detachComposable()
    }
    }
    return remember(viewModelStoreOwnerViewModel) {
    viewModelStoreOwnerViewModel.viewModelStore
    }
    }

    @Composable
    fun WithViewModelStoreOwner(
    key: Any?,
    content: @Composable () -> Unit,
    ) {
    CompositionLocalProvider(
    value = LocalViewModelStoreOwner provides rememberViewModelStoreOwner(key),
    content = content,
    )
    }

    @Stable
    private class ViewModelStoreOwnerViewModel(
    private var key: Any?,
    initialLifecycle: Lifecycle,
    ) : ViewModel() {

    private val attachedLifecycle = MutableStateFlow<Lifecycle?>(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()

    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    init {
    viewModelScope.launch {
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    .collectLatest {
    if (it == Lifecycle.Event.ON_DESTROY) {
    attachedLifecycle.update { null }
    }
    }
    }
    viewModelScope.launch {
    isAttachedToComposable.collectLatest { isAttached ->
    when {
    // If we are attached or we are destroyed, we do not need to do anything
    isAttached || attachedLifecycle.value == null -> return@collectLatest
    // If we are detached and the lifecycle state is resumed, we should reset the view model store
    attachedLifecycle.value?.currentState == Lifecycle.State.RESUMED -> resetViewModelStore()
    else -> {
    // We wait for the lifecycle event ON_RESUME to be triggered before resetting the ViewModelStore
    // If in the mean time we are attached again, this work is cancelled
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    // Wait for first event that matches ON_RESUME.
    .firstOrNull { it == Lifecycle.Event.ON_RESUME } ?: return@collectLatest
    resetViewModelStore()
    }
    }
    }
    }
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
    this.key = key
    resetViewModelStore()
    }
    attachedLifecycle.update { lifecycle }
    }

    fun attachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(true) }
    }

    fun detachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(false) }
    }

    override fun onCleared() {
    super.onCleared()
    resetViewModelStore()
    }

    private fun resetViewModelStore() {
    viewModelStore.viewModelStore.clear()
    }

    }
  5. @joost-klitsie joost-klitsie renamed this gist Aug 28, 2024. 1 changed file with 0 additions and 0 deletions.
  6. @joost-klitsie joost-klitsie revised this gist Aug 28, 2024. 1 changed file with 13 additions and 7 deletions.
    20 changes: 13 additions & 7 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -45,29 +45,35 @@ private class ViewModelStoreOwnerViewModel(
    initialLifecycle: Lifecycle,
    ) : ViewModel() {

    private val attachedLifecycle = MutableStateFlow(initialLifecycle)
    private val attachedLifecycle = MutableStateFlow<Lifecycle?>(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()

    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    init {
    viewModelScope.launch {
    attachedLifecycle
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    .collectLatest {
    if (it == Lifecycle.Event.ON_DESTROY) {
    attachedLifecycle.update { null }
    }
    }
    }
    viewModelScope.launch {
    isAttachedToComposable.collectLatest { isAttached ->
    when {
    // If we are attached or we are destroyed, we do not need to do anything
    isAttached || attachedLifecycle.value.currentState == Lifecycle.State.DESTROYED -> return@collectLatest
    isAttached || attachedLifecycle.value == null -> return@collectLatest
    // If we are detached and the lifecycle state is resumed, we should reset the view model store
    attachedLifecycle.value.currentState == Lifecycle.State.RESUMED -> resetViewModelStore()
    attachedLifecycle.value?.currentState == Lifecycle.State.RESUMED -> resetViewModelStore()
    else -> {
    // We wait for the lifecycle event ON_RESUME to be triggered before resetting the ViewModelStore
    // If in the mean time we are attached again, this work is cancelled
    attachedLifecycle
    .flatMapLatest { lifecycle ->
    // Make sure we stop listening to the lifecycle events once we are destroyed
    lifecycle.eventFlow.takeWhile { it != Lifecycle.Event.ON_DESTROY }
    }
    .flatMapLatest { lifecycle -> lifecycle?.eventFlow ?: emptyFlow() }
    // Wait for first event that matches ON_RESUME.
    .firstOrNull { it == Lifecycle.Event.ON_RESUME } ?: return@collectLatest
    resetViewModelStore()
  7. @joost-klitsie joost-klitsie created this gist Aug 28, 2024.
    105 changes: 105 additions & 0 deletions RememberViewModelStoreOwner.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,105 @@
    import androidx.compose.runtime.*
    import androidx.compose.ui.platform.LocalLifecycleOwner
    import androidx.lifecycle.*
    import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
    import androidx.lifecycle.viewmodel.compose.viewModel
    import kotlinx.coroutines.flow.*
    import kotlinx.coroutines.launch

    @Composable
    fun rememberViewModelStoreOwner(
    key: Any?,
    ): ViewModelStoreOwner {
    val viewModelKey = "rememberViewModelStoreOwner#" + currentCompositeKeyHash.toString(36)
    val localLifecycle = LocalLifecycleOwner.current.lifecycle
    val viewModelStoreOwnerViewModel = viewModel<ViewModelStoreOwnerViewModel>(key = viewModelKey) {
    ViewModelStoreOwnerViewModel(key, localLifecycle)
    }
    viewModelStoreOwnerViewModel.update(key, localLifecycle)

    DisposableEffect(Unit) {
    viewModelStoreOwnerViewModel.attachComposable()
    onDispose {
    viewModelStoreOwnerViewModel.detachComposable()
    }
    }
    return remember(viewModelStoreOwnerViewModel) {
    viewModelStoreOwnerViewModel.viewModelStore
    }
    }

    @Composable
    fun WithViewModelStoreOwner(
    key: Any?,
    content: @Composable () -> Unit,
    ) {
    CompositionLocalProvider(
    value = LocalViewModelStoreOwner provides rememberViewModelStoreOwner(key),
    content = content,
    )
    }

    @Stable
    private class ViewModelStoreOwnerViewModel(
    private var key: Any?,
    initialLifecycle: Lifecycle,
    ) : ViewModel() {

    private val attachedLifecycle = MutableStateFlow(initialLifecycle)
    private val isAttachedToComposable = MutableSharedFlow<Boolean>()

    val viewModelStore: ViewModelStoreOwner = object : ViewModelStoreOwner {
    override val viewModelStore = ViewModelStore()
    }

    init {
    viewModelScope.launch {
    isAttachedToComposable.collectLatest { isAttached ->
    when {
    // If we are attached or we are destroyed, we do not need to do anything
    isAttached || attachedLifecycle.value.currentState == Lifecycle.State.DESTROYED -> return@collectLatest
    // If we are detached and the lifecycle state is resumed, we should reset the view model store
    attachedLifecycle.value.currentState == Lifecycle.State.RESUMED -> resetViewModelStore()
    else -> {
    // We wait for the lifecycle event ON_RESUME to be triggered before resetting the ViewModelStore
    // If in the mean time we are attached again, this work is cancelled
    attachedLifecycle
    .flatMapLatest { lifecycle ->
    // Make sure we stop listening to the lifecycle events once we are destroyed
    lifecycle.eventFlow.takeWhile { it != Lifecycle.Event.ON_DESTROY }
    }
    // Wait for first event that matches ON_RESUME.
    .firstOrNull { it == Lifecycle.Event.ON_RESUME } ?: return@collectLatest
    resetViewModelStore()
    }
    }
    }
    }
    }

    fun update(key: Any?, lifecycle: Lifecycle) {
    if (key != this.key) {
    this.key = key
    resetViewModelStore()
    }
    attachedLifecycle.update { lifecycle }
    }

    fun attachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(true) }
    }

    fun detachComposable() {
    viewModelScope.launch { isAttachedToComposable.emit(false) }
    }

    override fun onCleared() {
    super.onCleared()
    resetViewModelStore()
    }

    private fun resetViewModelStore() {
    viewModelStore.viewModelStore.clear()
    }

    }