android / codelab-android-hilt

Apache License 2.0
350 stars 186 forks source link

Can't inject into Application class #5

Closed forntoh closed 4 years ago

forntoh commented 4 years ago

I am trying to inject a WorkManagerFactory into my Application class, I get the following error for the dependencies needed

[Dagger/MissingBinding] retrofit2.Retrofit.Builder cannot be provided without an @Inject constructor or an @Provides-annotated method.

The app builds successfully when I just remove the field in the Application class but I need it to inject dependencies into my WorkManager

Application class

@HiltAndroidApp
class App : Application(), Configuration.Provider {

    @Inject
    lateinit var refreshTokenSchedulerFactory: RefreshTokenSchedulerFactory

    override fun onCreate() {
        super.onCreate()
        FirebaseCrashlytics.getInstance().sendUnsentReports()
    }

    override fun getWorkManagerConfiguration(): Configuration =
            Configuration.Builder()
                    .setMinimumLoggingLevel(android.util.Log.DEBUG)
                    .setWorkerFactory(refreshTokenSchedulerFactory)
                    .build()
}

Work Manager factory

class RefreshTokenSchedulerFactory @Inject constructor(
        val preferencesHelper: PreferencesHelper,
        val dataManagerAuth: DataManagerAuth
) : WorkerFactory() {

    override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? =
            RefreshTokenScheduler(appContext, workerParameters, preferencesHelper, dataManagerAuth)
}

NetworkModule

@Module
@InstallIn(ActivityComponent::class)
object NetworkModule {

    @Provides
    fun provideBaseOkHttpClient(
            ikorInterceptor: IkorInterceptor,
            httpLoggingInterceptor: HttpLoggingInterceptor,
            connectivityInterceptor: ConnectivityInterceptor,
            receivedCookiesInterceptor: ReceivedCookiesInterceptor,
            sslSocketFactory: SSLSocketFactory,
            trustManager: TrustManager
    ): OkHttpClient = OkHttpClient.Builder()
            .sslSocketFactory(sslSocketFactory, trustManager as X509TrustManager)
            .hostnameVerifier(HostnameVerifier { _, _ -> true })
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .addInterceptor(httpLoggingInterceptor)
            .addInterceptor(connectivityInterceptor)
            .addInterceptor(ikorInterceptor)
            .addInterceptor(receivedCookiesInterceptor)
            .build()

    @Provides
    fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor()
            .setLevel(HttpLoggingInterceptor.Level.BODY)

    @Provides
    fun provideIkorInterceptor(preferencesHelper: PreferencesHelper): IkorInterceptor = IkorInterceptor(preferencesHelper)

    @Provides
    fun provideConnectivityInterceptor(@ApplicationContext context: Context): ConnectivityInterceptor = ConnectivityInterceptor(context)

    @Provides
    fun provideReceivedCookiesInterceptor(preferencesHelper: PreferencesHelper): ReceivedCookiesInterceptor = ReceivedCookiesInterceptor(preferencesHelper)

    @Provides
    fun provideRetrofitBuilder(): Retrofit.Builder = Retrofit.Builder()
            .baseUrl(BaseUrl.defaultBaseUrl)
            .addConverterFactory(NullOnEmptyConverterFactory())
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
}

BaseApiManager

class BaseApiManager @Inject constructor(
        retrofitBuilder: Retrofit.Builder,
        baseOkHttpClient: OkHttpClient
) {
...
}

DataManagerModule

@Module
@InstallIn(ActivityComponent::class)
object DataManagerModule {

    @Provides
    fun provideDataManagerAuth(
            baseApiManager: BaseApiManager
    ): DataManagerAuth = DataManagerAuth(baseApiManager)
    ...
}

DataManagerAuth

@Singleton
class DataManagerAuth @Inject constructor(
        private val baseApiManager: BaseApiManager
) {
...
}
manuelvicnt commented 4 years ago

Hi! Have you removed the default initialiser from the AndroidManifest.xml file? The Hilt docs mention it.

See this other link to the WorkManager docs to do that.

manuelvicnt commented 4 years ago

Also, your modules are installed in the ActivityComponent instead of the ApplicationComponent or SingletonComponent. If you're trying to inject that info in an Application, those bindings should be available there

forntoh commented 4 years ago

Thanks a lot, I made the module to be installed in ApplicationComponent, and have started using hilt's work manager factory.