Dagger Hilt Missing Binding on Fragment Module - android

Im working on trying to provide my API service into a FragmentModule but its not working the way I have setup my Dependency injection, Im receiving a MissingBiding Error even though I have include the corresponding modules into the FragmentModule.
This is my setup:
AppModule
#Module
#InstallIn(value = [SingletonComponent::class])
object AppModule {
#Provides
fun provideApplication(application: MyApplication): Context = application
}
NetworkModule
#Module(includes = [AppModule::class])
#InstallIn(value = [SingletonComponent::class])
object NetworkModule {
private const val BASE_URL = "https://url.co/"
#Provides
fun provideAPI(retrofit: Retrofit): APIService = retrofit.create(APIService::class.java)
#Provides
fun provideCache(cacheFile: File): Cache = Cache(cacheFile, 10 * 1024 * 1024)
#Provides
fun provideFile(#ApplicationContext context: Context): File = File(context.cacheDir, "okhttp_cache")
#Provides
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit =
Retrofit.Builder().client(okHttpClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor, cache: Cache, context: Context): OkHttpClient {
return OkHttpClient.Builder()
.cache(cache)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
}
}
MyFragmentModule
#Module(includes = [AppModule::class, NetworkModule::class])
#InstallIn(SingletonComponent::class)
object MyFragmentModule {
#Provides
fun provideMyRepositoryImpl(#IoDispatcher
dispatcher: CoroutineDispatcher,
functions: Functions,
apiService: APIService): MyRepository = MyRepositoryImpl(dispatcher, functions, apiService)
#Provides
fun provideMyUseCase(myRepository: MyRepository): MyUseCase = MyUseCase(myRepository)
}
[Dagger/MissingBinding]
C:\MyApplication_HiltComponents.java:168: error: [Dagger/MissingBinding] MyApplication cannot be provided without an #Inject constructor or an #Provides-annotated method. This type supports members injection but cannot be implicitly provided.
public abstract static class SingletonC implements MyApplication_GeneratedInjector,
^
A binding with matching key exists in component: MyApplication_HiltComponents.SingletonC
MyApplication is injected at
di.AppModule.provideApplication(application)
android.content.Context is injected at
di.NetworkModule.provideOkHttpClient(�, context)
okhttp3.OkHttpClient is injected at
di.NetworkModule.provideRetrofit(okHttpClient)
retrofit2.Retrofit is injected at
di.NetworkModule.provideAPI(retrofit)
data.service.APIService is injected at
ui.main_activity.ranking.di.MyFragmentModule.provideMyRepositoryImpl(�, apiService)
ui.main_activity.ranking.data.MyRepository.MyRepository is injected at
ui.main_activity.ranking.di.MyFragmentModule.provideMyUseCase(rankingMyRepository)
javax.inject.Provider<ui.main_activity.ranking.domain.MyUseCase> is injected at
ui.main_activity.ranking.data.view_model.RankingViewModel_AssistedFactory(MyUseCase)
ui.main_activity.ranking.data.view_model.RankingViewModel_AssistedFactory is injected at
ui.main_activity.ranking.data.view_model.RankingViewModel_HiltModule.bind(factory)
java.util.Map<java.lang.String,javax.inject.Provider<androidx.hilt.lifecycle.ViewModelAssistedFactory<? extends androidx.lifecycle.ViewModel>>> is injected at
androidx.hilt.lifecycle.ViewModelFactoryModules.ActivityModule.provideFactory(�, viewModelFactories)
#dagger.hilt.android.internal.lifecycle.DefaultActivityViewModelFactory java.util.Set<androidx.lifecycle.ViewModelProvider.Factory> is injected at
dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories.InternalFactoryFactory(�, defaultActivityFactorySet, �)
dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories.InternalFactoryFactory is requested at
dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories.ActivityEntryPoint.getHiltInternalFactoryFactory() [MyApplication_HiltComponents.SingletonC ? MyApplication_HiltComponents.ActivityRetainedC ? MyApplication_HiltComponents.ActivityC]
The following other entry points also depend on it:
dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories.FragmentEntryPoint.getHiltInternalFactoryFactory() [MyApplication_HiltComponents.SingletonC ? MyApplication_HiltComponents.ActivityRetainedC ? MyApplication_HiltComponents.ActivityC ? MyApplication_HiltComponents.FragmentC]
If you have any feedback, i'd very greatefull, thank you

For anyone who is facing a similar issue, be careful by how you defined your modules, in my case i had a #Provides with context instead of MyApp, I also included the #ApplicationContext in the network module, and that solved the issue
#Provides
fun provideApplication(application: MyApplication): MyApplication = application
Added the context annotation:
#Provides
fun provideFile(#ApplicationContext context: Context): File = File(context.cacheDir, "okhttp_cache")
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor, cache: Cache, #ApplicationContext context: Context): OkHttpClient {
return OkHttpClient.Builder()
.cache(cache)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
}

Related

#Provides methods can only be present within a #Module or #ProducerModule

I wrote network module in project. I checked all similiar codes and qustions there are some people have same problem. But they all didn't solve this problem for me. I don't know what is problem here.
This is the error:
error: #Provides methods can only be present within a #Module or #ProducerModule
public static final com.technoface.iga.api.BoardingPassService postBoardingPassesRead(#org.jetbrains.annotations.NotNull()
NetworkModule.kt
#Module
#InstallIn(SingletonComponent::class)
object NetworkModule {
#Singleton
#Provides
fun provideBaseUrl() = BuildConfig.BASE_URL
#Provides
#Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
}
#ServiceInterceptorOkHttpClient
#Singleton
#Provides
fun providesServiceInterceptor(clientPreferences: ClientPreferences): ServiceInterceptor =
ServiceInterceptor(clientPreferences)
#Provides
#Singleton
fun provideOkHttpClient(
logging: HttpLoggingInterceptor,
#ServiceInterceptorOkHttpClient
serviceInterceptor: ServiceInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(logging)
.addInterceptor(serviceInterceptor)
.build()
}
#Provides
#Singleton
fun provideNetworkResultCallAdapterFactory(): CallAdapter.Factory {
return NetworkResultCallAdapterFactory.create()
}
#Provides
#Singleton
fun provideRetrofit(client: OkHttpClient, callAdapterFactory: CallAdapter.Factory): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(callAdapterFactory)
.client(client)
.build()
}
#Provides
#Singleton
fun postBoardingPassesRead(serviceBuilder: ServiceBuilder): BoardingPassService = serviceBuilder.buildService(BoardingPassService::class.java)
#Qualifier
#Retention(AnnotationRetention.BINARY)
annotation class BaseUrl
#Qualifier
#Retention(AnnotationRetention.BINARY)
annotation class ServiceInterceptorOkHttpClient
BoardingPassServiceRepo.kt
class BoardingPassServiceRepo #Inject constructor(
private val boardingPassService: BoardingPassService
) {
suspend fun postBoardingPassesRead(boardingPassInfoRequest: BoardingPassInfoRequest) = boardingPassService.postBoardingPassesRead(
encryptData(boardingPassInfoRequest)
)
}
AppModule.kt
#Module
#InstallIn(SingletonComponent::class)
object AppModule {
#Singleton
#Provides
fun provideClientPreferences(
#ApplicationContext context: Context
) = ClientPreferences(context)
}
class BoardingPassServiceRepo #Inject constructor(
private val boardingPassService: BoardingPassService
) {
suspend fun postBoardingPassesRead(boardingPassInfoRequest: BoardingPassInfoRequest) = boardingPassService.postBoardingPassesRead(
encryptData(boardingPassInfoRequest)
)
}
Update Gradle version.
Changed gradle version.
Clean, Rebuild, Invalidate cache
Deactivated Antivirus.

Dagger/MissingBinding okhttp3.logging.HttpLoggingInterceptor cannot be provided without an #Inject constructor or an #Provides-annotated method

I am new with dagger-hilt. I can't solve this issue.
This is the error I'm facing :
\com\example\news\NewsApplication_HiltComponents.java:129: error: [Dagger/MissingBinding] okhttp3.logging.HttpLoggingInterceptor cannot be provided without an #Inject constructor or an #Provides-annotated method.
public abstract static class SingletonC implements NewsApplication_GeneratedInjector,
^
okhttp3.logging.HttpLoggingInterceptor is injected at
com.example.news.di.NetworkModule.provideOkHttpClient(interceptor)
okhttp3.OkHttpClient is injected at
com.example.news.di.NetworkModule.providesNewsService(�, okHttpClient)
com.example.news.api.NewsService is injected at
com.example.news.data.repository.NewsRepository(newsService)
com.example.news.data.repository.NewsRepository is injected at
com.example.news.presentation.viewmodel.NewsViewModel(newsRepository)
com.example.news.presentation.viewmodel.NewsViewModel is injected at
com.example.news.presentation.viewmodel.NewsViewModel_HiltModules.BindsModule.binds(arg0)
#dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.example.news.NewsApplication_HiltComponents.SingletonC ? com.example.news.NewsApplication_HiltComponents.ActivityRetainedC ? com.example.news.NewsApplication_HiltComponents.ViewModelC]
This is the Network module class:
#InstallIn(SingletonComponent::class)
#Module
object NetworkModule {
#Singleton
#Provides
fun providesRetrofit(): Retrofit.Builder {
return Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
}
#Singleton
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(interceptor).build()
}
#Singleton
#Provides
fun providesNewsService(retrofitBuilder: Retrofit.Builder, okHttpClient: OkHttpClient): NewsService {
return retrofitBuilder.client(okHttpClient).build().create(NewsService::class.java)
}
}
Need some help on this error. I don't understand why this error is coming.
Issue is resolved:
I was not using interceptor in addInterceptor()
#Singleton
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor) : OkHttpClient {
return OkHttpClient.Builder()**.addInterceptor(interceptor).**build()
}

dagger2 is throwing an error: cannot be provided without an #Provides-annotated method. in my android project's build

Hello folks please help me to debug this dagger2 issue,I am very new to dagger2 and just started with a project.
public abstract interface ApplicationComponent {
^
java.util.Map<java.lang.Class<?
>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<?>>> is injected at
dagger.android.DispatchingAndroidInjector(injectorFactoriesWithClassKeys, �)
dagger.android.DispatchingAndroidInjector<java.lang.Object> is injected at
com.example.dictionary.App.dispatchingServiceInjector
com.example.dictionary.App is injected at
com.example.dictionary.di.components.ApplicationComponent.inject(com.example.dictionary.App)
error: [Dagger/MissingBinding]
java.util.Map<java.lang.String,javax.inject.Provider<dagger.android.AndroidInjector.Factory<?
>>> cannot be provided without an #Provides-annotated method.
My implementations are:
interface ApiService {
companion object {
const val BASE_URL= "https://od-api.oxforddictionaries.com/"
}
#GET("api/v2/entries/en-gb/")
fun getMeaning(#Query("word") word: String): Observable<Response>
}
}
open class RemoteDataSource #Inject constructor(private val apiService: ApiService) {
fun getWordMeaning(word: String) = apiService.getMeaning(word)
}
#ApplicationScope
#Component(modules = [ApplicationModule::class, NetworkModule::class])
interface ApplicationComponent {
fun inject(app: App)
fun inject(mainActivity: MainActivity)
}
#Module
class ApplicationModule(private val application: Application) {
#ApplicationScope
#Provides
fun provideApplicationContext(): Context = application.applicationContext
#ApplicationScope
#Provides
fun provideSharedPreferences(): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(application)
#ApplicationScope
#Provides
fun providerDisplayMetrics(): DisplayMetrics = application.resources.displayMetrics
}
#Module
class NetworkModule(
private val baseUrl: String,
private val application: Application
) {
companion object {
const val CACHE_SIZE = 10 * 1024 * 1024L // 10 MiB
const val TIME_OUT = 10L // time in minutes to get the response from server
}
#ApplicationScope
#Provides
fun provideGson(): Gson = GsonBuilder().create()
#ApplicationScope
#Provides
fun provideOkHttpCache() = Cache(application.cacheDir, CACHE_SIZE)
#ApplicationScope
#Provides
fun provideOkHttpClient(cache: Cache): OkHttpClient = with(OkHttpClient.Builder()) {
writeTimeout(3, TimeUnit.MINUTES)
.connectTimeout(3, TimeUnit.MINUTES)
.readTimeout(TIME_OUT, TimeUnit.MINUTES)
cache(cache)
addInterceptor(headersInterceptor())
build()
}
#ApplicationScope
#Provides
fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
#ApplicationScope
#Provides
fun provideApiService(retrofit: Retrofit): ApiService =
retrofit.create(ApiService::class.java)
private var authRequest: String? = null
private fun headersInterceptor() = Interceptor { chain ->
val requestBuilder = chain.request().newBuilder()
requestBuilder.addHeader("Accept", "application/json")
requestBuilder.addHeader("app_id", "SOME APP ID")
requestBuilder.addHeader("app_key", "Some API KEY")
chain.proceed(
requestBuilder.build()
)
}
}
class App : Application(), HasAndroidInjector {
#Inject
lateinit var dispatchingServiceInjector:
DispatchingAndroidInjector<Any>
override fun onCreate() {
super.onCreate()
applicationComponent.inject(this)
RxJavaPlugins.setErrorHandler {
it.printStackTrace()
}
}
override fun androidInjector(): AndroidInjector<Any> {
return dispatchingServiceInjector
}
val applicationComponent: ApplicationComponent by
lazy<ApplicationComponent>(mode = LazyThreadSafetyMode.NONE) {
DaggerApplicationComponent
.builder()
.applicationModule(ApplicationModule(this))
.networkModule(NetworkModule(ApiService.BASE_URL, this))
.build()
}
}
I tried re-building the code, also attempted invalidate cache and restart to re-install dependencies, as dagger2 requires re-building the project every time once a new dependency injection is implemented, followed YouTube tutorials, to implement this so far, but unable to detect the problem, although in the build crash its indicating to provide #Provides, but in my NetworkModule, ApplicationModule I set this #Provides annotation.
Please help to figure out the solution.
As suggested in this answer, just add your App class in the android manifest under the application tag.
<application ...
android:name = ".App" ...>
...

Screen rotation problem in viewmodel with dagger-hilt with injection

I have a problem with injection dagger into view model.The problem is that losing form inputs when rotating the screen.Is the problem in my injection or initialize my view model? Here is my viewmodel;
#HiltViewModel
class ProfilIslemViewModel #Inject constructor(application: Application,
private val kullaniciService: KullaniciService,
private val kullaniciDao:KullaniciDao
): AndroidViewModel(application), CoroutineScope {...}
And here is my fragment that use this view model;
#AndroidEntryPoint
class ProfilIslemFragment:Fragment(), ProfilIslemFragmentClickListener {
private val viewModel: ProfilIslemViewModel by viewModels();
...
}
Here is the module that injected class;
#Module
#InstallIn(SingletonComponent::class)
object KutuphanemAppModule {
#Singleton
#Provides
fun provideKutuphanemDatabase
(#ApplicationContext context:Context) = Room.databaseBuilder(
context,
KutuphanemDatabase::class.java,
KUTUPHANEM_DB_NAME
).build();
#Singleton
#Provides
fun provideRetrofit(client: OkHttpClient):Retrofit =
Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
#Singleton
#Provides
fun provideHttpClient(customSharedPreferences: CustomSharedPreferences):OkHttpClient{
return OkHttpClient.Builder().addInterceptor(object:Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
val request:Request = chain.request().newBuilder().addHeader("Authorization",
"Bearer "+customSharedPreferences.getStringFromSharedPreferences(APP_TOKEN_KEY).trim()).build();
return chain.proceed(request);
}
}).build();
}
#Singleton
#Provides
fun provideParametreDao(database: KutuphanemDatabase) = database.getParametreDao();
#Singleton
#Provides
fun provideParametreApi(retrofit: Retrofit):IParametreService = retrofit.create(IParametreService::class.java);
#Singleton
#Provides
fun provideKullaniciApi(retrofit: Retrofit):KullaniciService = retrofit.create(KullaniciService::class.java);
#Singleton
#Provides
fun provideKitapApi(retrofit: Retrofit):IKitapService = retrofit.create(IKitapService::class.java);
#Singleton
#Provides
fun provideKullaniciDao(database: KutuphanemDatabase) = database.getKullaniciDao();
}
When I rotate the screen the inputs are losing. How to solve this problem?
I found the error. It is not relevant my view model or injections. It caused by two way databinding. But even so I put this line into the contructor of viewmodel;
private val savedStateHandle: SavedStateHandle
I am controlling the state with this param.So my inputs are not losing.

Provide application context with dagger 2

Good day all,
I would like to provide application context for my AppModule class.
I would like to have a PrefsHelper be provided through out the application like I do with my ApiService class.
The code for my AppModule:
#Module
#Suppress("unused")
object AppModule {
#Provides
#Reusable
#JvmStatic
internal fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
/**
* Provides the Retrofit object.
* #return the Retrofit object
*/
#Provides
#Reusable
#JvmStatic
internal fun provideRetrofitInterface(): Retrofit {
val interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
this.level = HttpLoggingInterceptor.Level.BODY
}
val client: OkHttpClient = OkHttpClient.Builder().apply { this.addInterceptor(interceptor) }.build()
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(GsonConverterFactory.create())
.build()
}
The way I have seen it done before (In Java) is create a constructor and pass in the application context in that way. Kotlin doesnt allow that with an object
How can I have the context be provided in this class allowing me to provide PrefsHelper?
You could also use the BindsInstance annotation in your AppComponent.
So your AppComponent would look something like this:
#Singleton
#Component(modules = YOUR_MODULES)
interface AppComponent {
//Whatever injections you have
#Component.Builder
interface Builder {
fun build(): AppComponent
#BindsInstance
fun application(Application application): Builder
}
}
Then you just add the new methods to your AppComponent creation in your Application class.
DaggerAppComponent.builder().application(this).build()
Change your AppModule to something like this:
#Module
class AppModule(private val application: Application) {
#Singleton
#Provides
internal fun provideApplication(): Application = application
#Singleton
#Provides
internal fun providePrefs(application: Application): YourPref {
return YourPref(application)
}
}

Categories

Resources