30

我有一个名为 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,并且一切正常。

我得到了 ViewModel ListFragment,选择了使用它的值DetailFragment

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

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

4

6 回答 6

23

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

回到 shared ViewModelStore,比如说你希望它成为你的 Application 实例。您需要您的应用程序来实现ViewModelStoreOwner.

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

    override fun getViewModelStore(): ViewModelStore {
        return appViewModelStore
    }
}

然后在您知道需要在活动边界之间共享 ViewModel 的情况下,您可以执行类似的操作。

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

所以现在它将使用您的应用程序中定义的商店。这样您就可以共享 ViewModel。

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

于 2018-05-19T01:31:03.440 回答
5

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

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

以这种方式创造出来ViewModel的东西一直活着,直到它的最后一个LifeCycleOwner被摧毁。

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

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

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

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

于 2019-08-21T06:35:17.217 回答
4

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

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)`

这将只提供您可以在活动之间共享的 UserProfileViewModel 的单个对象。

于 2017-12-14T06:21:02.790 回答
2

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

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

让我们举一个简单的例子:

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

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

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

于 2018-11-01T18:29:56.953 回答
2

如果您想要一个由您的所有活动(而不是某些活动)共享的 ViewModel,那么为什么不将您想要存储在该 ViewModel 中的内容存储在您的 Application 类中呢?

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

于 2019-01-11T09:25:04.103 回答
-3

这是一个链接

希望它可以帮助你。O(∩_∩)O~

此外:

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

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

3)如果您使用 dagger2 在两个活动(可能是三个)之间共享视图模型,这里ViewModelFactory示例

于 2018-07-31T05:06:13.487 回答