简体   繁体   中英

How To Replace DaggerAppComponent During Hilt Migration - Android Dependency Injection

I'm migrating our app from Dagger 2 to Hilt. I'm fairly new to all of this and having a very tough time.

In the BaseApplication I'm trying to replace the AppComponent, which is currently built with the DaggerAppComponent builder.

There are references to the AppComponent all over the codebase, so I'm not sure how to remove/replace this functionality.

BaseApplication.kt

open class BaseApplication : Application() {
    
    ...

    lateinit var appComponent: AppComponent
        private set

    ...

    appComponent = DaggerAppComponent.builder()
            .appModule(AppModule(this))
            .build()

    appComponent.inject(this)
}

AppComponent.kt

@Singleton
@Component(modules = [AppModule::class, NetworkService::class, AnalyticsModule::class])
interface AppComponent {

    fun providesNetworkService(): NetworkService

    fun inject(activity: MapActivity)
    fun inject(viewModel: NetworkBaseViewModel)
    fun inject(application: BaseApplication)
    fun inject(contactsDataSourceFactory: ContactsDataSourceFactory)
    fun inject(contactDetailViewModel: ContactDetailViewModel)
    fun inject(contactDetailFragment: ContactDetailFragment)
    fun inject(contactDetailEditFragment: ContactDetailEditFragment)
    fun inject(contactDetailCreateFragment: ContactDetailCreateFragment)
    fun inject(contactsListViewModel: ContactsListViewModel)
    fun inject(activityFeedViewModel: ActivityFeedViewModel)
    fun inject(httpService: BaseHttpService)
    fun inject(httpService: BaseWebService.ClientWrapper)
    fun inject(pdfViewerFragment: PDFViewerFragment)
    fun inject(commuteTimeManager: CommuteTimeManager)
    fun inject(verifyLoginWorker: VerifyLoginWorker)
    fun inject(loginWebFragment: LoginWebFragment)
}

Here's where the problem starts. I updated the AppModule by annotating it with @InstallIn(SingletonComponent::class) and replacing the parameters with @Inject constructor() . According to the errors, the constructor on a Module must be empty.

AppModule.kt

@InstallIn(SingletonComponent::class) // <- Added
@Module
// class AppModule(private val application: BaseApplication) { // <-Removed
class AppModule @Inject constructor() { // <- Added

    // Old Code:
    // @Provides
    // @Singleton
    // fun provideApplication(): BaseApplication  = application

    // @Provides
    // @Singleton
    // internal fun provideContext(): Context = application

    // New Code:
    @Provides
    @Singleton
    fun provideApplication(@ApplicationContext application: BaseApplication): BaseApplication {
        return application as BaseApplication
    }

}

Now in the DaggerAppComponent builder I have an error:

Too many arguments for public constructor AppModule() defined in com.companyname.db.dependencyinjection.AppModule

appComponent = DaggerAppComponent.builder()
                .appModule(AppModule(this)) // <- Here is the error
                .build()

If I can't add a constructor to AppModule , how am I supposed to work around this?

** Note: I am trying to migrate the app piece by piece since there are a lot of moving parts here, which is why I haven't removed the AppComponent altogether. Maybe there's something I'm missing in there though. I've been following along the migration guide and have experimented with adding/removing the aggregator entry point.

Example of use of AppComponent NetworkBaseViewModel.kt

open class NetworkBaseViewModel (application: Application): BaseViewModel(application) {

    ...

    init {
        @Suppress("LeakingThis")
        (application.applicationContext as? BaseApplication)?.appComponent?.inject(this@NetworkBaseViewModel)

    ...
}

You don't have to do this when using Hilt:

appComponent = DaggerAppComponent.builder()
    .appModule(AppModule(this))
    .build()

All you have to do is to annotate your Application class with @HiltAndroidApp . Since your BaseApplication is open , I assume you'd have to do it in the Application class that extends it.

You also don't have to do this in your NetworkBaseViewModel:

(application.applicationContext as? BaseApplication)?.appComponent?.inject(this@NetworkBaseViewModel)

Now you just annotate your ViewModel with @HiltViewModel and when you want to inject something into your ViewModel, you annotate the constructor with @Inject and make it's dependencies injectable (either by constructor injection or with Modules ). For example:

@HiltViewModel
class NetworkViewModel @Inject constructor(
    private val retrofitService: ExampleRetrofitService
) : ViewModel() {

    // ViewModel stuff

}

Also your AppModule doesn't even need a constructor with @Inject annotation because you don't inject anything into it. See the example Module here , it's just an object .

Finally, I recommend reading this guide -> Dependency injection with Hilt

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM