user4383363
user4383363

Reputation:

viewModelFactory variable has not been initialized when utilizing fragments

Now, this error is showing when I try to run my app in my device

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property viewModelFactory has not been initialized

This project is using fragments, unlike the previous project when the above worked.

class MainFragment : Fragment() {
    private lateinit var binding: FragmentMainBinding
    private lateinit var adapter: MainAdapter
    private lateinit var viewModel: MainViewModel
    @Inject lateinit var viewModelFactory: MainViewModelFactory
    ...
    private fun populateUi() {
        viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
        ...
    }
}

MainViewModelFactory:

class MainViewModelFactory @Inject constructor(private val mainViewModel: MainViewModel) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return mainViewModel as T
        }

        throw IllegalArgumentException("Unknown class name")
    }
}

I also have this module:

@Module
class ViewModelModule {
    @Provides
    @Singleton
    fun provideMainViewModel(factory: MainViewModelFactory): ViewModelProvider.Factory = factory
}

being used in my AppComponent:

@Singleton
@Component(modules = [
    AndroidInjectionModule::class,
    BuilderModule::class,
    AppModule::class,
    NetworkModule::class,
    DaoModule::class,
    ViewModelModule::class
])
interface AppComponent {
    fun inject(app: App)
}

And this module that uses @ContributeAndroidInjector for activity and fragments

@Module
abstract class BuilderModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeMainFragment(): MainFragment
}

The root of the app, which previously had only the activity injection:

class App : Application(), HasActivityInjector, HasSupportFragmentInjector {
    @Inject
    lateinit var activityInjector: DispatchingAndroidInjector<Activity>

    @Inject
    lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent
            .builder()
            .appModule(AppModule(this))
            .networkModule(NetworkModule("https://jsonplaceholder.typicode.com/"))
            .build()
            .inject(this)
    }

    override fun activityInjector(): AndroidInjector<Activity> {
        return activityInjector
    }

    override fun supportFragmentInjector(): AndroidInjector<Fragment> {
        return fragmentInjector
    }
}

The previous app I built did not make use of fragments, and I still think it could be this the reason it fails in this project that does use fragments.

Upvotes: 4

Views: 3905

Answers (1)

user4383363
user4383363

Reputation:

I solved this by adding

override fun onAttach(context: Context?) {
    super.onAttach(context)
    AndroidSupportInjection.inject(this)
}

But I'd like to do as the same in the activity. Why doesn't it work as well, using the BuilderModule?

Upvotes: 8

Related Questions