5

From official we know

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way

But i think lot of developers use ViewModel as both data store and controller(like calling repository, network client for data). I also use as for both data store and controller for view.

Android official sample code has also some controller logic. From official :

class MyViewModel : ViewModel() {
  private val users: MutableLiveData<List<User>> by lazy {
     MutableLiveData().also {
        loadUsers()
     }
  }

  fun getUsers(): LiveData<List<User>> {
    return users
  }

  private fun loadUsers() {
    // Do an asynchronous operation to fetch users.
  }
}

Here loadUsers may calling some Repository or NetworkClient . So here it acting like controller.

I am sure many developer do this way, but as from definition ViewModel should store and manage UI related data, should ViewModel act as a Controller ?

I found some stackoverflow thread this and this about this.

First one accepted answer suggested not to use use ViewModel as Controller and to use a Controller for other task.

In comment section of Second one @commonsware also suggested not to use complicated things other than data.

So my question is

  1. What will be the actual responsibility of ViewModel from architectural concept?
  2. If i have to do some method calls related to View [like data query, network call and other business login related stuff ] where should i do it?
  3. and if i have to use a Controller then how i connect View and Controller for device rotation and sharing controller between Fragment ?

Hope my question is clear to all

Thanks in advance.

Abu Yousuf
  • 5,729
  • 3
  • 31
  • 50

1 Answers1

3

Here loadUsers() may calling some Repository or NetworkClient . So here it acting like controller.

I am sure many developer do this way, but as from definition ViewModel should store and manage UI related data, should ViewModel act as a Controller ?

Theoretically, the retrieval of data should be internal to the LiveData, triggered by having active observers and based on that, deciding what to do (in onActive()). If the LiveData is actually a MediatorLiveData, then this also applies to any block bound with addSource, as the block added with addSource of a MediatorLiveData is only called when the MediatorLiveData is observed by an active observer

You can see this technique used to its fullest in the NetworkBoundResource. The ViewModel only stores data, and knows nothing of data loading.

What will be the actual responsibility of ViewModel from architectural concept?

If you see the comments by Yigit Boyar (creator of ViewModel):

I'm the guy (or part of the team) that added it and it had nothing to do w/ MVVM. It is all about trying to give a class to people where they should put the data.

AAC is not an MVVM implementation, nor VM concept only lives as part of MVVM.

In fact, the main motivation for this was; we've been telling devs not to manage data in the UI controller and the answers was also, so where? And ViewModel became that answer.

We want it to be the model for your view layer (fragment, activity whatever). On the hindsight, it could be better to pick a name that is new but naming is really hard.

In conclusion: ViewModel is the Model in an MVC scenario, where C is the Activity or Fragment, V is the inflated view, and M is the ViewModel.

If i have to do some method calls related to View [like data query, network call and other business login related stuff ] where should i do it?

ViewModel gets the data in the form of a LiveData, and the LiveData is "activated" by observing it from the View with a given lifecycle.

Network calls are supposed to be also triggered in the same manner (if you follow the approach as per LiveData was designed).

In theory, if you have a login call, you could as well do it in the controller instead of the model, so you could do it in the Fragment, even though there are tricks like Jetpack Databinding that would let you call methods from the View on the Model directly from the XML.

and if i have to use a Controller then how i connect View and Controller for device rotation and sharing controller between Fragment ?

ViewModel exposes LiveData and can potentially also expose LiveEvent if you write the necessary code for that (unfortunately that is not provided by the Jetpack team, and neither are Command bindings), and either the View or the Controller can call methods directly on it if necessary. ViewModel is stored across config changes (not across process death, ofc) so it should not hold a direct view reference.

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • 1
    Thanks for answer. If i use `Controller` then how i share same instance of `Controller` between `Fragments` ? like i do[sharing same VM instance between fragments] with `ViewModel` now. making `Controller` Singletone ? – Abu Yousuf May 30 '20 at 09:29
  • if the retrieval of data should be internal to the `LiveData` then for every `LiveData` i have to inject `Repository` or `DataSource` in `LiveData` right ? – Abu Yousuf May 30 '20 at 09:35
  • The "controller" is the Fragment. The "model" is the ViewModel. You can share ViewModel between Fragments by using a shared superscope (Activity, or NavBackStackEntry, or something custom that has a ViewModelStore), you can't share Fragments between Fragments (technically you can with `findFragmentByTag`, but it's tricky). To invoke a Repository method without the LiveData actually knowing about the Repository itself, you can pass the Repository ref from the ViewModel to the LiveData on creation and the method to invoke as a lambda, see https://stackoverflow.com/a/54004612/2413303 – EpicPandaForce May 30 '20 at 09:48
  • If i use `Fragment` as Controller then i have to put lot of code on it like lot of business logic then it becomes complex and break the Single Responsibility. View shouldn't have other code else managing views – Abu Yousuf May 30 '20 at 11:06
  • You don't have to confine your terms and modeling to "model", "view" and "controller". If you want to create a new class for something as it makes more sense over there instead of here, then do so. – EpicPandaForce May 30 '20 at 12:37