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

时间:2018-03-19 13:47:08

标签: java android android-livedata

示例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;
    }

}

主要活动:

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

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

3 个答案:

答案 0 :(得分:24)

当您致电ViewModelProviders.of(this)时,实际上您创建/保留了绑定到ViewModelStore的{​​{1}},因此不同的活动有不同的this和每个ViewModelStore使用给定工厂创建ViewModelStore的不同实例,因此您不能在不同的ViewModel s中拥有ViewModel的相同实例。

但是您可以通过传递充当单件工厂的自定义ViewModel工厂的单个实例来实现此目的,因此它将始终在不同活动中传递ViewModelStore的同一实例。

例如:

ViewModel

所以你需要的是使public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory { NameViewModel t; public SingletonNameViewModelFactory() { // t = provideNameViewModelSomeHowUsingDependencyInjection } @Override public NameViewModel create(Class<NameViewModel> modelClass) { return t; } } 单身(例如使用Dagger)并像这样使用它:

SingletonNameViewModelFactory

注意:

在不同的范围内保留mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class); 是一种反模式。强烈建议您保留数据层对象(例如,制作数据源或存储库单例)并在不同范围(活动)之间保留数据。

阅读this文章了解详情。

答案 1 :(得分:9)

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

您可以做的是将数据保存在不同的层中,例如存储库,它可以是单例,也可以使用相同的视图模型。

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

答案 2 :(得分:0)

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

您的ViewModel Factory就像

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

还有您的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 }
            }
    }
}

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

ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(NameViewModel::class.java)

OR

创建扩展功能以方便访问

fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
    ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)