Share ViewModel between fragments that are in different Activity

故事扮演 提交于 2019-11-28 21:19:44

A little late but you can accomplish this using a shared ViewModelStore. Fragments and activities implement the ViewModelStoreOwner interface. In those cases fragments have a store per instance and activities save it in a static member (I guess so it can survive configuration changes).

Getting back to the shared ViewModelStore, let say for example that you want it to be your Application instance. You need your application to implement ViewModelStoreOwner.

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

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

Then in the cases when you know that you need to share ViewModels between activity boundaries you do something like this.

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

So now it will use the Store defined in your app. That way you can share ViewModels.

Very important. Because in this example the ViewModels live in your application instance they won't be destroyed when the fragment/activity that uses them gets destroyed. So you will have to link them to the lifecycle of the last fragment/activity that will use them, or manually destroy them.

you can use factory to make viewmodel and this factor will return single object of view model.. As:

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]
    }
}
}

In Activity:

viewModelFactory = Injection.provideViewModelFactory(this)

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

This will provide only single object of UserProfileViewModel which you can share between Activities.

If you want a ViewModel that is shared by all your activities (as opposed to some), then why not store what you want stored in that ViewModel inside your Application class?

The trend presented at the last Google I/O seems to be to abandon the concept of Activities in favor of single-activity apps that have a lot of Fragments. ViewModels are the way to remove the great number of interfaces the activity of an interface formerly had to implement. Thus this aproach no longer makes for giant and unmaintainable activities.

Well, I created a library for this purpose named Vita, You can share ViewModels between activities and even fragments with different host activity:

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

The created ViewModel in this way stay alive until its last LifeCycleOwner is destroyed.

Also you can create ViewModels with application scope:

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

And this type of ViewModel will be cleared when user closes app

Give it a try and kindly let me know your feedback: https://github.com/FarshadTahmasbi/Vita

I think we still get confused with the MVVM framework on Android. For another activity, do not get confused because it must necessarily be the same, why?

This makes sense if it has the same logic (even if the logic could still be abstract in other useful classes), or if the view in the XML is almost identical.

Let's take a quick example:

I create a ViewModel called vmA, and an activity called A and I need the user's data, I will go to insert the repository in vmA of the User.

Now, I need another activity that needs to read user data, I create another ViewModel called vmB and in it I will call the user repository. As described, the repository is always the same.

Another way already suggested is to create N instances of the same ViewModel with the implementation of the Factory.

Here's a link

Hope it helps you. O(∩_∩)O~

In addition:

1) The inspiration for the code came from smart pointer in c++.

2) It will be auto cleared when no activities or fragments references ShareViewModel. The ShareViewModel # onShareCleared() function will be called at the same time! You don't need to destroy them manually!

3) If you use dagger2 to inject the ViewModelFactory for share the viewmodel
between two activities (maybe three), Here's sample

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!