java Android LiveData - 如何在不同的活动上重用相同的 ViewModel?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49364550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 10:20:38  来源:igfitidea点击:

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

javaandroidandroid-livedata

提问by user1209216

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?

我想调用mModel.getCurrentName().setValue(anotherName);第二个活动并使 MainActivity 接收更改。那可能吗?

回答by Saeed Masoumi

When you call ViewModelProviders.of(this), you actually create/retain a ViewModelStorewhich is bound to this, so different Activities have different ViewModelStoreand each ViewModelStorecreates a different instance of a ViewModelusing a given factory, so you can not have the same instance of a ViewModelin different ViewModelStores.

当您调用 时ViewModelProviders.of(this),您实际上创建/保留了一个ViewModelStore绑定到的this,因此不同的活动具有不同的ViewModelStore并且每个都使用给定的工厂ViewModelStore创建不同的 a 实例ViewModel,因此您不能ViewModel在不同的ViewModelStores 中拥有相同的 a 实例。

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 ViewModelamong different activities.

但是您可以通过传递作为单例工厂的自定义 ViewModel 工厂的单个实例来实现这一点,因此它始终会ViewModel在不同的活动之间传递相同的实例。

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 SingletonNameViewModelFactorysingleton (e.g. using Dagger) and use it like this:

所以你需要做的是SingletonNameViewModelFactory单例(例如使用 Dagger)并像这样使用它:

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).

ViewModel在不同范围内保留s 是一种反模式。强烈建议保留您的数据层对象(例如,使您的 DataSource 或 Repository 成为单例)并在不同范围(活动)之间保留您的数据。

Read thisarticle for details.

阅读这篇文章了解详情。

回答by TotoliciCristian

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.

当使用 ViewModelProviders 获取视图模型时,您将作为生命周期所有者传递给 MainActivity,这将为该活动提供视图模型。在第二个活动中,您将获得该 ViewModel 的不同实例,这次是您的第二个活动。第二个模型将有第二个实时数据。

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.

您可以做的是在不同的层中维护数据,例如存储库,它可能是一个单例,这样您就可以使用相同的视图模型。

enter image description here

在此处输入图片说明

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
...
}

回答by Amir Raza

Simply create the instance of your ViewModel, in this case NameViewModel

只需创建ViewModel的实例,在本例中为NameViewModel

Your ViewModel Factory be like

你的 ViewModel 工厂就像

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

还有你的 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 ViewModelProvidersto get the same instance of your ViewModel to use in any activity

现在,您可以使用ViewModelProviders来获取 ViewModel 的相同实例以在任何活动中使用

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)