SharedViewModel without using ActivityViewModel

Emre Hamurcu
3 min readJan 8, 2024

--

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

--

--