提问人:user1209216 提问时间:3/19/2018 最后编辑:ColdFireuser1209216 更新时间:2/14/2022 访问量:39087
Android LiveData - 如何在不同的活动中重用相同的 ViewModel?
Android LiveData - how to reuse the same ViewModel on different activities?
问:
示例 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);
我想调用第二个活动并使 MainActivity 接收更改。这可能吗?mModel.getCurrentName().setValue(anotherName);
答:
当你调用 时,你实际上创建/保留了绑定到 的 ,所以不同的 Activity 有不同的,并且每个 Activity 都使用给定的工厂创建不同的 a 实例,因此你不能在不同的 s 中拥有相同的 a 实例。ViewModelProviders.of(this)
ViewModelStore
this
ViewModelStore
ViewModelStore
ViewModel
ViewModel
ViewModelStore
但是,您可以通过传递自定义 ViewModel 工厂的单个实例来实现此目的,该实例充当单例工厂,因此它将始终在不同的活动之间传递相同的实例。ViewModel
例如:
public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
NameViewModel t;
public SingletonNameViewModelFactory() {
// t = provideNameViewModelSomeHowUsingDependencyInjection
}
@Override
public NameViewModel create(Class<NameViewModel> modelClass) {
return t;
}
}
所以你需要做的是制作单例(例如使用匕首)并像这样使用它:SingletonNameViewModelFactory
mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);
注意:
在不同作用域之间保留 s 是一种反模式。强烈建议保留数据层对象(例如,将 DataSource 或存储库设置为单一实例),并在不同范围(活动)之间保留数据。ViewModel
有关详细信息,请阅读本文。
评论
ViewModel
ViewModelProviders.of(getActivity()).get(NameViewModel.class)
当使用作为生命周期所有者传递的 ViewModelProviders 获取视图模型时,这将为该活动提供视图模型。在第二个活动中,您将获得该 ViewModel 的不同实例,这次是第二个 Activity。第二个模型将具有第二个实时数据。
您可以做的是将数据维护在不同的层中,例如存储库,这可能是一个单一实例,这样您就可以使用相同的视图模型。
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
...
}
评论
LiveData in repositories: To avoid leaking ViewModels and callback hell, repositories can be observed
只需创建 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 }
}
}
}
现在,您可以使用 ViewModel 的相同实例在任何活动中使用ViewModelProviders
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(NameViewModel::class.java)
或
创建扩展功能,方便访问
fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)
评论
ViewModel 范围/生命周期与活动相关联,仅仅是因为传递给 ViewModelProvider 构造函数的 ViewModelStoreOwner 恰好是该活动。
由于您需要提供 ViewModelStoreOwner,因此您可以轻松地提供具有更长生命周期的 ViewModelStoreOwner,例如应用程序。
您可以
- 提供你自己的 Application 子类,并使其实现 ViewModelStoreOwner(并具有 ViewModelStore)
- 在 ViewModelProvider 构造函数调用中,传递 activity.application 而不是 activity。
这将导致 ViewModelProvider 与应用程序级 ViewModelStore 交互,从而允许您创建具有应用程序范围的 ViewModel 实例。
评论