SharedViewModel without using ActivityViewModel
Communication between fragments within an Android app often poses a challenge, especially when it comes to sharing data and logic seamlessly. As developers, we seek efficient solutions to bridge these gaps and ensure smooth interaction between different parts of our application. One effective approach involves the clever utilization of ViewModelStoreOwner
to enable shared ViewModels among fragments.
In the realm of Android Architecture Components, ViewModelStoreOwner
plays a pivotal role. It serves as a conduit for the creation and management of ViewModels, ensuring their lifecycle aligns with the owner's lifecycle. You can see the ViewModelStoreOwner
explanations from the doc.
/**
* Class to store `ViewModel`s.
*
* An instance of `ViewModelStore` must be retained through configuration changes:
* if an owner of this `ViewModelStore` is destroyed and recreated due to configuration
* changes, new instance of an owner should still have the same old instance of
* `ViewModelStore`.
*
* If an owner of this `ViewModelStore` is destroyed and is not going to be recreated,
* then it should call [clear] on this `ViewModelStore`, so `ViewModel`s would
* be notified that they are no longer used.
*
* Use [ViewModelStoreOwner.getViewModelStore] to retrieve a `ViewModelStore` for
* activities and fragments.
*/
open class ViewModelStore {
// I deleted other methods, please focus on map and clear func.
// Holds viewModels into map
private val map = mutableMapOf<String, ViewModel>()
// Clears `ViewModel`s that they are no longer used
fun clear() {
for (vm in map.values) {
vm.clear()
}
map.clear()
}
}
What’s the problem with activityViewModels
If your viewModel scopes to activity this means your viewModel onCleared func will never be fired, that means this viewModel will be alive until your activity is destroyed. If your viewModel holds data, this can cause a problem because you may want to start your flow from scratch, but you cannot because your viewModel scopes to your activity. Basically we can say that it is a singleton object in the scope of the activity.
Implementing Shared ViewModels
Let's create a ViewModel and share it between our Fragment.
class SharedViewModel() : ViewModel() {
var data: String = "SharedViewModel Data"
}
class HomeFragment : Fragment(R.layout.fragment_home) {
// SharedViewModel will be alive until fragment detached
private val viewModel by viewModels<SharedViewModel>()
companion object {
const val TAG = "HomeFragment"
fun newInstance() = HomeFragment()
}
}
class DetailFragment : Fragment(R.layout.fragment_detail) {
// We can get the ownerProducer from HomeFragment.TAG
// because it is on back stack.
private val viewModel by viewModels<SharedViewModel>(
ownerProducer = {
findOwnerProducerWithTag(HomeFragment.TAG)
}
)
companion object {
const val TAG = "DetailFragment"
fun newInstance() = DetailFragment()
}
}
fun Fragment.findOwnerProducerWithTag(tag: String): ViewModelStoreOwner {
return activity?.supportFragmentManager?.findFragmentByTag(tag)
?: this
}
Conclusion
Leveraging ViewModelStoreOwner
to enable shared ViewModels among fragments significantly enhances an app's modularity and efficiency. By following this approach, developers can streamline communication and data sharing between fragments, leading to a more robust and maintainable application architecture.
Subscribe for more : https://youtu.be/TosfhUp7LrU