'Android LiveData - how to reuse the same ViewModel on different activities?
Example ViewModel:
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
}
Main activity:
mModel = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = textView::setText;
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this, nameObserver);
I want to call mModel.getCurrentName().setValue(anotherName); in second activity and make MainActivity receive changes. Is that possible?
Solution 1:[1]
When getting the view model using the ViewModelProviders you are passing as lifecycle owner the MainActivity, this will give the view model for the that activity. In the second activity you will get a different instance of that ViewModel, this time for your second Activity. The second model will have a second live data.
What you can do is maintain the data in a different layer, like a repository, which may be a singleton and that way you can use the same view model.
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = DataRepository.getInstance().getCurrentName();
}
return mCurrentName;
}
}
//SingleTon
public class DataRepository
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
//Singleton code
...
}
Solution 2:[2]
Simply create the instance of your ViewModel, in this case NameViewModel
Your ViewModel Factory be like
class ViewModelFactory : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>) =
with(modelClass){
when {
isAssignableFrom(NameViewModel::class.java) -> NameViewModel.getInstance()
else -> throw IllegalArgumentException("Unknown viewModel class $modelClass")
}
} as T
companion object {
private var instance : ViewModelFactory? = null
fun getInstance() =
instance ?: synchronized(ViewModelFactory::class.java){
instance ?: ViewModelFactory().also { instance = it }
}
}
}
And your ViewModel
class NameViewModel : ViewModel() {
//your liveData objects and many more...
companion object {
private var instance : NameViewModel? = null
fun getInstance() =
instance ?: synchronized(NameViewModel::class.java){
instance ?: NameViewModel().also { instance = it }
}
}
}
Now you can use ViewModelProviders to get the same instance of your ViewModel to use in any activity
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(NameViewModel::class.java)
OR
create an extension function for easier access
fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)
Solution 3:[3]
ViewModel scope/lifecycle is tied to an activity simply because the ViewModelStoreOwner that you pass to the ViewModelProvider constructor happens to be the activity.
Since you get to provide the ViewModelStoreOwner, you can just as easily provide one that has a longer lifecycle, such as the application.
You can
- Provide your own subclass of Application and make it implement ViewModelStoreOwner (and have a ViewModelStore)
- In ViewModelProvider constructor calls, pass activity.application rather than activity.
This will cause the ViewModelProvider to interact with the application-level ViewModelStore, allowing you to create ViewModel instances that will have application scope.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Amir Raza |
| Solution 3 |

