Android LiveData - how to reuse the same ViewModel on different activities?

后端 未结 3 1616
情歌与酒
情歌与酒 2020-12-14 15:13

Example ViewModel:

public class NameViewModel extends ViewModel {
    // Create a LiveData with a String
    private MutableLiveData mCurrentNa         


        
相关标签:
3条回答
  • 2020-12-14 15:43

    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)
    
    0 讨论(0)
  • 2020-12-14 15:48

    When you call ViewModelProviders.of(this), you actually create/retain a ViewModelStore which is bound to this, so different Activities have different ViewModelStore and each ViewModelStore creates a different instance of a ViewModel using a given factory, so you can not have the same instance of a ViewModel in different ViewModelStores.

    But you can achieve this by passing a single instance of a custom ViewModel factory which acts as a singleton factory, so it will always pass the same instance of your ViewModel among different activities.

    For example:

    public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    
    
        NameViewModel t;
    
        public SingletonNameViewModelFactory() {
          //  t = provideNameViewModelSomeHowUsingDependencyInjection
        }
    
        @Override
        public NameViewModel create(Class<NameViewModel> modelClass) {
            return t;
        }
    }
    

    So what you need is to make SingletonNameViewModelFactory singleton (e.g. using Dagger) and use it like this:

    mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);
    

    Note:

    Preserving ViewModels among different scopes is an anti-pattern. It's highly recommended to preserve your data-layer objects (e.g. make your DataSource or Repository singleton) and retain your data between different scopes (Activities).

    Read this article for details.

    0 讨论(0)
  • 2020-12-14 16:02

    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
    ...
    }
    
    0 讨论(0)
提交回复
热议问题