[英]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单例),并在不同范围(活动)之间保留数据。
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.