-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ViewModel onClear not called when do bottom navigation with compose #52
Comments
Thanks for reporting this issue. I am currently on holiday and out of the country, so my replies to this issue will be rather slow in the next few weeks. However, I don't quite understand why this is a problem for you, so you might need to explain in more detail what you are trying to achieve and why this behaviour is not appropriate for you. This behaviour is what I would expect, given the example code that you linked. In the example, when you press the "back" button, the EmptyBehavior.Action {
composableManager.setActiveContainer(redController)
true
} The "true" being returned from the For example:
Is there a reason that you want to completely destroy the backstack when another tab is selected? This shouldn't be too difficult to add as an option, but I am wary of doing so because it doesn't feel like the correct thing to me. |
Hi @isaac-udy , thanks for the reply. Totally got your point, when switching bottom tabs, there are good reasons we should keep the viewModels for each tab. Maybe I'm not make it clear enough before. A sample for the issueI made a sample here: https://github.com/mengdd/enro-bottom-navigation-sample A brief introduction:
When user exit the app and back from launcher or recent app, go to the dashboard tab: ExpectedWe suppose when MainActivity onDestroy, the tabs' viewModel will all be cleared. Maybe I'm not using Enro in right way, or not combining it with Hilt correctly? The expected behavior would be somehow make the viewmodel |
Thank you for putting together that example. I misunderstood your original message, and thought the ViewModels were only being cleared when the Activity was being destroyed. The behaviour you're seeing is definitely a bug! I won't be able to release a proper fix that's integrated with the library until I am back in New Zealand, but I will look into a temporary workaround for you now. |
I believe I have a temporary fix for this issue. Here's the code: package /* whatever you like */
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.*
/**
* This object contains a temporary fix for an issue with Enro reported here: https://github.com/isaac-udy/Enro/issues/52
* To apply this fix, call `EnroComposableViewModelFix.applyFix` in an Activity's onCreate method, immediately after
* the call to `super.onCreate()`
*
* Example:
* ```
* class ExampleActivity : AppCompoatActivity() {
* override fun onCreate() {
* super.onCreate(savedInstanceState)
* EnroComposableViewModelFix.applyFix(this)
* }
* }
* ```
*/
@Suppress("UNCHECKED_CAST")
object EnroComposableViewModelFix {
fun applyFix(activity: FragmentActivity) {
activity.executeImmediatelyBeforeClearingViewModelStore {
activity.getComposableDestinationContextReferences()
.forEach {
it as LifecycleOwner
val lifecycleRegistry = it.lifecycle as LifecycleRegistry
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
}
}
private fun FragmentActivity.executeImmediatelyBeforeClearingViewModelStore(block: () -> Unit) {
// This is the same way that the base ComponentActivity uses to determine
// if a ViewModelStore will be cleared or not, and this will execute
// See the ComponentActivity constructor (around line 250) to see the original code
lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations) {
block()
}
}
})
}
// Returns a list of all the top level "dev.enro.core.compose.ComposableDestinationContextReference" instances
// that are owned by a particular Activity. This method relies on reflection to access internal Enro classes.
private fun FragmentActivity.getComposableDestinationContextReferences(): List<Any> {
val destinationStorageClass = Class.forName("dev.enro.core.compose.EnroDestinationStorage") as Class<ViewModel>
val destinationStorageInstance = ViewModelProvider(this).get(destinationStorageClass)
val getDestinationsMethod = destinationStorageClass.getMethod("getDestinations")
val destinationMap = (getDestinationsMethod.invoke(destinationStorageInstance) as Map<String, Map<String, Any>>)
return destinationMap.values.flatMap { it.values }
}
} To apply this fix, call A proper fix will be included with the next release of Enro. I will leave this issue open to post updates about the fix included with the next release of Enro, or to answer any questions/solve any problems related to the temporary fix. Let me know if you have any questions. |
- Clear composable destinations viewModelStores on EnroDestinationStorage clearing - Update active navigation context now checks lifecycleOwner's lifecycle instead of going through the NavigationHandle, to avoid crash after closing host activity - Added tests to cover both of these cases # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # Date: Mon Feb 21 11:43:53 2022 +1300 # # On branch issue-56 # Your branch is up to date with 'origin/issues/56'. # # Changes to be committed: # modified: enro-core/src/main/java/dev/enro/core/compose/ComposableContainer.kt # modified: enro-core/src/main/java/dev/enro/core/controller/lifecycle/NavigationLifecycleController.kt # modified: enro/src/androidTest/AndroidManifest.xml # modified: enro/src/androidTest/java/dev/enro/TestDestinations.kt # modified: enro/src/androidTest/java/dev/enro/core/ActivityToComposableTests.kt #
- Clear composable destinations viewModelStores on EnroDestinationStorage clearing - Update active navigation context now checks lifecycleOwner's lifecycle instead of going through the NavigationHandle, to avoid crash after closing host activity - Added tests to cover both of these cases
Background:
Using enro version: 1.6.0
Setup Bottom Navigation with Enro, UI is 100% built using Compose.
The MainActivity's code is similar with sample code here: https://github.com/isaac-udy/Enro/blob/b4ecd50c9acdf01ce2a003038ea4b87e01d720f0/example/src/main/java/dev/enro/example/MultistackCompose.kt
Each tab's content UI is built with Compose, and has its own ViewModel.
The issue
The
onCleared()
method of each tab's ViewModel will never be invoked, even if hitting back button until MainActivity destroy.The code:
If one of my tab's UI code is like this:
And the ViewModel is injected by Hilt:
Some clues
Dive into the code for a while, found the ViewModel clear logic is located here:
Enro/enro-core/src/main/java/dev/enro/core/compose/ComposableDestination.kt
Line 75 in b4ecd50
It waits an ON_DESTROY event to trigger the clear action.
But actually the lifecycle events only hitted ON_PAUSE:
Enro/enro-core/src/main/java/dev/enro/core/compose/ComposableDestination.kt
Line 161 in b4ecd50
Not sure under which condition it will hit ON_DESTROY:
Enro/enro-core/src/main/java/dev/enro/core/compose/ComposableDestination.kt
Line 137 in b4ecd50
The text was updated successfully, but these errors were encountered: