简体   繁体   English

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

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

Example ViewModel: 示例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); 我想调用mModel.getCurrentName().setValue(anotherName); in second activity and make MainActivity receive changes. 在第二个活动中,并使MainActivity接收更改。 Is that possible? 那可能吗?

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 ViewModelStore s. 当你调用ViewModelProviders.of(this) ,实际上创建/保留ViewModelStore这势必会this ,所以不同的活动有不同的ViewModelStore每个ViewModelStore创建的不同实例ViewModel使用给定的工厂,所以你不能有不同ViewModelStore中的ViewModel相同实例。

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. 但是,您可以通过传递充当单例工厂的自定义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 SingletonNameViewModelFactory singleton (eg using Dagger) and use it like this: 因此,您需要使SingletonNameViewModelFactory单身(例如,使用Dagger)并像这样使用它:

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

Note: 注意:

Preserving ViewModel s among different scopes is an anti-pattern. 在不同范围之间保留ViewModel是一种反模式。 It's highly recommended to preserve your data-layer objects (eg make your DataSource or Repository singleton) and retain your data between different scopes (Activities). 强烈建议保留您的数据层对象(例如,使您的DataSource或Repository单例),并在不同范围(活动)之间保留数据。

Read this article for details. 阅读文章的详细信息。

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. 当使用ViewModelProviders获取视图模型时,您将以生命周期所有者MainActivity的身份进行传递,这将为该活动提供视图模型。 In the second activity you will get a different instance of that ViewModel, this time for your second Activity. 在第二个活动中,您将获得另一个ViewModel实例,这是您的第二个活动。 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
...
}

Simply create the instance of your ViewModel , in this case NameViewModel 只需创建ViewModel的实例,在本例中为NameViewModel

Your ViewModel Factory be like 您的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 }
            }
    }
}

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 ViewModelProviders to 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM