在不同活动中的片段之间共享视图模型



我有一个名为 SharedViewModel 的 ViewModel:

public class SharedViewModel<T> extends ViewModel {
private final MutableLiveData<T> selected = new MutableLiveData<>();

public void select(T item) {
selected.setValue(item);
}
public LiveData<T> getSelected() {
return selected;
}
}

我已经根据Google的Arch ViewModel参考页面上的SharedViewModel示例实现了它:

https://developer.android.com/topic/libraries/architecture/viewmodel.html#sharing_data_between_fragments

活动中两个或多个片段需要相互通信是很常见的。这从来都不是微不足道的,因为两者都是 片段需要定义一些接口描述和所有者 活动必须将两者绑定在一起。此外,两个片段都必须 处理尚未创建或未创建其他片段的情况 可见。

我有两个片段,分别叫ListFragmentDetailFragment.

到目前为止,我在一个名为MasterActivity的活动中使用了这两个片段,一切都运行良好。

我在ListFragment中获得了ViewModel,选择了要在DetailFragment上使用它的值。

mStepSelectorViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

但是,现在,在某些情况下,我需要将ListFragment(不同设备配置的布局)添加到称为DetailActivity的不同活动中。有没有办法像上面的例子一样做到这一点?

有点晚了,但您可以使用共享ViewModelStore来完成此操作。片段和活动实现ViewModelStoreOwner接口。在这些情况下,片段每个实例都有一个存储,活动将其保存在静态成员中(我猜这样它就可以在配置更改中幸存下来)。

回到共享ViewModelStore,例如,假设您希望它成为您的应用程序实例。您需要您的应用程序来实现ViewModelStoreOwner

class MyApp: Application(), ViewModelStoreOwner {
private val appViewModelStore: ViewModelStore by lazy {
ViewModelStore()
}
override fun getViewModelStore(): ViewModelStore {
return appViewModelStore
}
}

然后,当您知道需要在活动边界之间共享 ViewModels 时,您可以执行类似操作。

val viewModel = ViewModelProvider(myApp, viewModelFactory).get(CustomViewModel::class.java)

因此,现在它将使用应用中定义的应用商店。这样您就可以共享视图模型。

非常重要。因为在此示例中,ViewModels存在于应用程序实例中,当使用它们的片段/活动被销毁时,它们不会被销毁。因此,您必须将它们链接到将使用它们的最后一个片段/活动的生命周期,或手动销毁它们。

好吧,我为此目的创建了一个名为 Vita 的库,您可以在活动之间共享ViewModel,甚至可以共享具有不同主机活动的片段:

val myViewModel = vita.with(VitaOwner.Multiple(this)).getViewModel<MyViewModel>()

以这种方式创建的ViewModel保持活力,直到其最后LifeCycleOwner被摧毁。

您还可以创建具有应用程序范围的ViewModel

val myViewModel = vita.with(VitaOwner.None).getViewModel<MyViewModel>()

当用户关闭应用程序时,这种类型的ViewModel将被清除

试一试,请让我知道您的反馈: https://github.com/FarshadTahmasbi/Vita

您可以使用工厂来制作视图模型,此因子将返回视图模型的单个对象。如:

class ViewModelFactory() : ViewModelProvider.Factory {
override fun create(modelClass: Class): T {
if (modelClass.isAssignableFrom(UserProfileViewModel::class.java)) {
val key = "UserProfileViewModel"
if(hashMapViewModel.containsKey(key)){
return getViewModel(key) as T
} else {
addViewModel(key, UserProfileViewModel())
return getViewModel(key) as T
}
}
throw IllegalArgumentException("Unknown ViewModel class")
}
companion object {
val hashMapViewModel = HashMap<String, ViewModel>()
fun addViewModel(key: String, viewModel: ViewModel){
hashMapViewModel.put(key, viewModel)
}
fun getViewModel(key: String): ViewModel? {
return hashMapViewModel[key]
}
}
}

在活动中:

viewModelFactory = Injection.provideViewModelFactory(this)
// Initialize Product View Model
userViewModel = ViewModelProviders.of(this, viewModelFactory).get(
UserProfileViewModel::class.java)`

这将仅提供用户配置文件视图模型的单个对象,您可以在活动之间共享该对象。

我认为我们仍然对Android上的MVVM框架感到困惑。 对于另一个活动,不要混淆,因为它必须相同,为什么?

如果它具有相同的逻辑(即使该逻辑在其他有用的类中仍然是抽象的),或者 XML 中的视图几乎相同,则这是有意义的。

让我们举个简单的例子:

我创建了一个名为 vmA 的 ViewModel,以及一个名为 A 的活动,我需要用户的数据,我将去将存储库插入用户的 vmA 中。

现在,我需要另一个需要读取用户数据的活动, 我创建了另一个名为 vmB 的 ViewModel,并在其中调用用户存储库。 如前所述,存储库始终相同。

已经建议的另一种方法是使用工厂的实现创建同一 ViewModel 的 N 个实例。

如果您想要一个由您的所有活动(而不是某些活动)共享的 ViewModel, 那为什么不将您想要存储在该视图模型中的内容存储 在您的应用程序类中?

在上一次Google I/O上呈现的趋势似乎是放弃活动的概念,转而支持具有大量片段的单活动应用程序。 ViewModels 是删除接动以前必须实现的大量接口的方法。 因此,这种缺陷不再造成巨大且无法维护的活动。

这是一个链接

希望对您有所帮助。O(∩_∩)O~

另外:

1)代码的灵感来自smart pointer in c++

2)当没有活动或片段引用时,它将自动清除ShareViewModelShareViewModel # onShareCleared()函数将同时调用! 您无需手动销毁它们!

3) 如果使用 dagger2 注入ViewModelFactory以便在两个活动(可能是三个)之间共享视图模型
,下面是示例

相关内容

  • 没有找到相关文章

最新更新