Search code examples
androidkotlindagger-2dagger

Can't initialize viewmodel Dagger + Extension Function


I'm trying to create an extension function that return a viewmodel by lazy, but i get an error about viewmodelFactory in't initialized, when i use the by lazy in the same Fragment works fine,

Example (Works fine):

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private val listViewModel by lazy {
        ViewModelProvider(this, viewModelFactory)[ListViewModel::class]
    }

But when I extract it to an Extension function this fails

Example (Error):

inline fun <reified VM : ViewModel> Fragment.provideViewModel(
    viewModelFactory: ViewModelProvider.Factory
): Lazy<VM> = lazy {
    ViewModelProvider(this, viewModelFactory)[VM::class.java]
}
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private val listViewModel by provideViewModel<ListViewModel>(viewModelFactory)


Solution

  • Having a look at what happens behind the scenes, it seems like inline functions are the cause. When you decompile the Kotlin code into Java you see that Kotlin treats an inline function with a special wrapper class which unfortunately takes in the function arguments as constructor parameters:

    this.viewModel$delegate = LazyKt.lazy((Function0)(new ActivityMain$$special$$inlined$provideViewModel$1(this, viewModelFactory$iv)));
    

    so it requires viewModelFactory$iv which represents the lateinit factory to be initialised:

    Factory var10001 = this.fac;
    if (var10001 == null) {
        Intrinsics.throwUninitializedPropertyAccessException("fac");
    }
    androidx.lifecycle.ViewModelProvider.Factory viewModelFactory$iv = (androidx.lifecycle.ViewModelProvider.Factory)var10001;
    

    So this is clearly an issue with Kotlin and Dagger's interoperability and I doubt has any solution other than to change the way you're implementing things.