Android LiveData - 如何在不同的活动中重用同一个 ViewModel?
Android LiveData - how to reuse the same ViewModel on different activities?
示例视图模型:
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;
}
}
主要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);
我想在第二个 activity 中调用 mModel.getCurrentName().setValue(anotherName);
并使 MainActivity 接收更改。这可能吗?
当你调用 ViewModelProviders.of(this)
时,你实际上 create/retain 一个绑定到 this
的 ViewModelStore
,所以不同的 Activity 有不同的 ViewModelStore
并且每个 ViewModelStore
使用给定的工厂创建 ViewModel
的不同实例,因此您不能在不同的 ViewModelStore
中拥有相同的 ViewModel
实例。
但是您可以通过传递充当单例工厂的自定义 ViewModel 工厂的单个实例来实现此目的,因此它将始终在不同的活动之间传递 ViewModel
的相同实例。
例如:
public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
NameViewModel t;
public SingletonNameViewModelFactory() {
// t = provideNameViewModelSomeHowUsingDependencyInjection
}
@Override
public NameViewModel create(Class<NameViewModel> modelClass) {
return t;
}
}
所以你需要制作 SingletonNameViewModelFactory
单例(例如使用 Dagger)并像这样使用它:
mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);
注:
在不同范围之间保留 ViewModel
s 是 anti-pattern。强烈建议保留您的 data-layer 对象(例如,使您的数据源或存储库单例)并在不同范围(活动)之间保留您的数据。
阅读 this 文章了解详情。
当使用您作为生命周期所有者传递给 MainActivity 的 ViewModelProvider 获取视图模型时,这将为 activity 提供视图模型。在第二个 activity 中,您将获得该 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
...
}
只需创建 ViewModel 的实例,在本例中为 NameViewModel
你的 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 }
}
}
}
还有你的 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 实例以在任何 activity
中使用
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 scope/lifecycle 与 activity 绑定只是因为您传递给 ViewModelProvider 构造函数的 ViewModelStoreOwner 恰好是 activity.
由于您要提供 ViewModelStoreOwner,因此您可以轻松地提供一个具有更长生命周期的对象,例如应用程序。
你可以
- 提供您自己的 Application 子类并使其实现 ViewModelStoreOwner(并拥有一个 ViewModelStore)
- 在 ViewModelProvider 构造函数调用中,传递 activity.application 而不是 activity。
这将导致 ViewModelProvider 与 application-level ViewModelStore 交互,允许您创建具有应用程序范围的 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;
}
}
主要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);
我想在第二个 activity 中调用 mModel.getCurrentName().setValue(anotherName);
并使 MainActivity 接收更改。这可能吗?
当你调用 ViewModelProviders.of(this)
时,你实际上 create/retain 一个绑定到 this
的 ViewModelStore
,所以不同的 Activity 有不同的 ViewModelStore
并且每个 ViewModelStore
使用给定的工厂创建 ViewModel
的不同实例,因此您不能在不同的 ViewModelStore
中拥有相同的 ViewModel
实例。
但是您可以通过传递充当单例工厂的自定义 ViewModel 工厂的单个实例来实现此目的,因此它将始终在不同的活动之间传递 ViewModel
的相同实例。
例如:
public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
NameViewModel t;
public SingletonNameViewModelFactory() {
// t = provideNameViewModelSomeHowUsingDependencyInjection
}
@Override
public NameViewModel create(Class<NameViewModel> modelClass) {
return t;
}
}
所以你需要制作 SingletonNameViewModelFactory
单例(例如使用 Dagger)并像这样使用它:
mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);
注:
在不同范围之间保留 ViewModel
s 是 anti-pattern。强烈建议保留您的 data-layer 对象(例如,使您的数据源或存储库单例)并在不同范围(活动)之间保留您的数据。
阅读 this 文章了解详情。
当使用您作为生命周期所有者传递给 MainActivity 的 ViewModelProvider 获取视图模型时,这将为 activity 提供视图模型。在第二个 activity 中,您将获得该 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
...
}
只需创建 ViewModel 的实例,在本例中为 NameViewModel
你的 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 }
}
}
}
还有你的 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 实例以在任何 activity
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 scope/lifecycle 与 activity 绑定只是因为您传递给 ViewModelProvider 构造函数的 ViewModelStoreOwner 恰好是 activity.
由于您要提供 ViewModelStoreOwner,因此您可以轻松地提供一个具有更长生命周期的对象,例如应用程序。
你可以
- 提供您自己的 Application 子类并使其实现 ViewModelStoreOwner(并拥有一个 ViewModelStore)
- 在 ViewModelProvider 构造函数调用中,传递 activity.application 而不是 activity。
这将导致 ViewModelProvider 与 application-level ViewModelStore 交互,允许您创建具有应用程序范围的 ViewModel 实例。