在不同Activity中的片段之间共享ViewModel

时间:2017-06-19 22:51:13

标签: android android-fragments android-activity viewmodel android-architecture-lifecycle

我有一个名为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的其他活动中。有没有办法像上面的例子那样做?

6 个答案:

答案 0 :(得分:10)

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

回到共享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)

现在它将使用您应用中定义的商店。这样你就可以共享ViewModels。

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

答案 1 :(得分:3)

好吧,我为此创建了一个名为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

答案 2 :(得分:2)

你可以使用factory来制作viewmodel,这个因素将返回视图模型的单个对象。作为:

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的单个对象,您可以在活动之间共享。

答案 3 :(得分:1)

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

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

让我们举个简单的例子:

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

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

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

答案 4 :(得分:1)

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

上一届Google I / O大会上提出的趋势似乎是放弃“活动”的概念,而转而使用具有很多“片段”的单活动应用程序。 ViewModels是删除接口以前必须实现的接口的大量方法。 因此,这种方式不再导致巨大且不可维持的活动。

答案 5 :(得分:-2)

这里是a link

希望它对您有帮助。 O(∩_∩)O〜

此外:

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

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

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