Advanced ViewModels (part III): Sharing data between Fragments.

Lucas Nobile
3 min readSep 15, 2020

--

ViewModel as the bridge between the View and the Model.

TL;DR: We can pass parameters to our ViewModel, use it as a data holder, also to share data between Fragments, and to persist its state across process recreation.

Sharing a View Model can be useful in the following scenarios:

  1. Master/Detail flow.
  2. Main View with a Modal (Dialog, BottomSheet, etc).

In our case, we have a Master/Detail flow: ShowNewsFragment allows the user to search for news and NewsDetailFragment will show the selected news detail.

We can archive this by creating a shared ViewModel with Activity Context:

private val viewModel: SharedNewsViewModel by activityViewModels { SharedNewsViewModel.Factory(newsService) }

Per documentation, by activityViewModels is a property delegate to get a reference to the ViewModel scoped to its Activity. So, our shared ViewModel will survive across Fragment recreation.

Having in mind that our ViewModel is a data holder, let’s create the LiveData we do want to share between our Fragments:

private val _selectedNews = MutableLiveData<News>()

And the corresponding getter and setter for the selected news:

fun setSelectedNews(news: News) {
_selectedNews.value = news
}
fun getSelectedNews() = _selectedNews.value

Then, in NewsDetailFragment we need to access to same shared ViewModel:

private val viewModel: SharedNewsViewModel by activityViewModels()

⚠️ Notice that there is no need to pass a Factory because here we are getting the ViewModel reference that was previously created in ShowNewsFragment.

Finally, and also in NewsDetailFragment, we need to get and to show the selected news:

override fun onViewCreated(view: View, savedInstanceState: Bundle?){
super.onViewCreated(view, savedInstanceState)

viewModel.getSelectedNews()?.let { news ->
with(binding) {
ivNews.loadUrl(news.urlToImage)
tvTitle.text = news.title
tvAuthor.text = news.author}
...
}
}
}

⚠️ Have you noticed that we are not using a Bundle to pass data to a Fragment? Based on the fact that our ViewModel is a data holder, we can forget about the TransactionTooLargeException and its size limit of 1MB when we are dealing with Bundles and passing data between Activities or Fragment arguments because we are accessing LiveData values instead.

⚠️ When using a shared ViewModel we do not observe the shared LiveData in the Detail or Modal view, we just get the value from the shared LiveData. Basically, if we observe the shared LiveData in a Detail or Modal view we will get a new event as soon as we start observing it because the shared LiveData has an existing value that was posted in the Master or Main View and this can leads to undesired results if we are observing states (Loading, Success, Error) and performing an operation based on those states.

Let me share with you all the repo:

And my tech talk about Advanced ViewModels on Android for GDG Córdoba, Argentina (in Spanish):

Please, continue reading the next posts in this multi-part series for more tips regarding advanced ViewModels 🙌

--

--