17

I am using Koin library in Kotlin for DI

Koin providing by viewmodel() for get instance of ViewModel by sharedViewModel() to get same instance in fragments.

How can I get same instance of the ViewModel in activities ? I didn't find any way to achieve this.

Sahil Arora
  • 495
  • 1
  • 3
  • 11

4 Answers4

7

After some research or discussion on architecture level and also report and issue github Koin,i found solution for this In this scenario,We should save that state/data into Repository which we need to share between multiple activities not in the viewModel and two or more different ViewModels can access same state/data that are saved in single instance of repository

see here

Sahil Arora
  • 495
  • 1
  • 3
  • 11
  • 1
    This is not the correct answer, since ViewModel is able to be shared between views by definition. Google has been encouraging MVVM design exactly because with it we don't need do things like this answer propose. MVVM architecture is a declarative and reactive approach. Insert and restore data from database every time you need share it is much more costly for the application. In my opinion this answer is about a MVP approach not MVVM. If you want something more imperative and bureaucratic consider moving your architecture to MVP or MVC. – Jean Patricio Jun 22 '21 at 19:24
  • 1
    You have probably solved your problem but this does not answer the question `How to share same instance of ViewModel between Activities using Koin DI?` – Some random IT boy Jan 13 '22 at 11:39
2

I would suggest making the app a ViewModelStoreOwner and injecting the viewModels using as owner the app. The code required would look like this

class App : Application(), ViewModelStoreOwner {
    private val mViewModelStore = ViewModelStore()

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

You can define some extensions to easily inject the viewModels


val Context.app: App
    get() = applicationContext as App

inline fun <reified T : ViewModel> Context.appViewModel(
    qualifier: Qualifier? = null,
    noinline state: BundleDefinition? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> {
    return lazy(LazyThreadSafetyMode.NONE) {
        GlobalContext.get().getViewModel(qualifier, state, { ViewModelOwner.from(app, null) }, T::class, parameters)
    }
}

inline fun <reified T : ViewModel> Fragment.appViewModel(
    qualifier: Qualifier? = null,
    noinline state: BundleDefinition? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> {
    return lazy(LazyThreadSafetyMode.NONE) {
        GlobalContext.get().getViewModel(qualifier, state, { ViewModelOwner.from(requireContext().app, null) }, T::class, parameters)
    }
}

You can then inject your viewModel like this

class MainActivity : AppCompatActivity() {
    private val mAppViewModel: AppViewModel by appViewModel()
}

The advantage of this solution is that you don't need to recreate the view model and if you decide to save the state between app restarts, you can easily make the app an SavedStateRegistryOwner as well and using the SavedStateHandle save/restore your state from inside the viewModel, being now bound to the process lifecycle.

Catalin
  • 119
  • 2
  • 4
1

you need to read more about ViewModel to understand it better. https://developer.android.com/topic/libraries/architecture/viewmodel

ViewModel is connected to your Activity

so you can share your Activities ViewModel only between his Fragments ,

that is what mean sharedViewModel in koin

sharedViewModel is the same if you use ViewModel Factory with same context .

sharing any data between Activities can be done via Intent , there is no another way in Android,

or you can keep some static / global data and share it between Activities

Hayk Melkonyan
  • 2,110
  • 4
  • 16
  • 22
  • i know about ViewModel Pattern but using ViewModel Custom Factory we can share Single viewmodel instance with different activities so my question is there any way in koin to provide custom ViewModel Factory See here https://developer.android.com/reference/android/arch/lifecycle/ViewModelProvider.Factory – Sahil Arora Aug 21 '19 at 09:59
  • @SahilArora ok . if you share some data between your activities , no matter how you will do it, you will have following problems 1. it must be static 2. you will have memory leaks . 3. android created Intents, and any cases if you want to do customize data providing between activities you will meet static(global) and of course memory leaks. – Hayk Melkonyan Aug 22 '19 at 12:37
0

I know this is very very late but you can try this: if you are extending a baseviewmodel, you need to declare the baseViewmodel as a single then in your respective activity inject the BaseViewModel. Practical example:

val dataModule = module {
    single { BaseViewModel(get(), get()) }
}

in your ViewModel

class LoginViewModel(private val param: Repository,
                            param1: Pref,
                            param2: Engine) : BaseViewModel(param1, param2)

Then in your activity class

val baseViewModel: BaseViewModel by inject()

Hope this help someone.

Ekenne Chilex
  • 45
  • 2
  • 8