I am trying to inject retrofit APIServices dependency into the model class. Here is My API Module Source Code:
#Module
#InstallIn(SingletonComponent::class)
object ApiModule {
#Singleton
#Provides
fun providesHttpLoggingInterceptor() = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
#Singleton
#Provides
fun providesOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient =
OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.build()
#Singleton
#Provides
fun providesRetrofit(okHttpClient: OkHttpClient): Retrofit =
Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.client(okHttpClient)
.build()
#Singleton
#Provides
#Named("ApiService")
fun providesApiService(retrofit: Retrofit):ApiServices =
retrofit.create(ApiServices::class.java)
}
For User Registration, I am using MVP Architecture Pattern where FragmentRegistration.kt is view layer, RegistrationModel is model layer class
When I inject ApiServices dependency into FragmentRegistration, it works fine. But when I try to inject it into model layer class, which is RegistrationModel, It doesn't work.
RegistrationModel:
class RegistrationModel(
val presenter: RegistrationContract.Presenter
) : RegistrationContract.Model {
#Inject
#Named("ApiService")
lateinit var apiServices: ApiServices
override fun onDataReady(registrationData: RegistrationData) {
val map = mapOf(
"Accept" to "application/json",
"Content-Type" to "application/json"
)
apiServices.userRegistration(map, registrationData)
.enqueue(object : Callback<RegistrationResponse> {
override fun onResponse(
call: Call<RegistrationResponse>,
response: Response<RegistrationResponse>
) {
if (response.isSuccessful) {
Log.d(TAG, "onDataReady: ${response.body().toString()}")
} else {
val apiFailure = APIFailure(
response.code(),
response.message()
)
presenter.onSignupFailure(apiFailure)
Log.d(TAG, "onDataReady: Error ${response.code()}")
Log.d(TAG, "onDataReady: Error Body ${response.errorBody()}")
}
}
override fun onFailure(call: Call<RegistrationResponse>, t: Throwable) {
presenter.onSignupFailure(
APIFailure(-1, t.toString())
)
Log.d(TAG, "onFailure: $t")
}
})
}
companion object {
const val TAG = "RegistrationModel"
}
}
In the above's Code,
#Inject
#Named("ApiService")
lateinit var apiServices: ApiServices
this dependency injection is not working.
You are trying to inject a filed provided by Hilt into a class which is not managed by Hilt. This will not work out of the box. You have to define EntryPoint for you custom class, so the Hilt can perform injection. You can read how to do that here: https://developer.android.com/training/dependency-injection/hilt-android#not-supported
Related
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" ...>
...
I just got a problem to inject repository in the interceptor to get access token when its needed or rather expired. I just don't understand where I did something wrong. I just didn't find any example how to deal with interceptor and repository. Thinking about that double "Retrofit.Builder" maybe this is a problem. What do you think? And let's the code talk:
#Module
class AppModule {
#Singleton
#Provides
fun provideRefreshTokenService(client: OkHttpClient): RefreshTokenApi {
return Retrofit.Builder()
.baseUrl("https://id.twitch.tv/oauth2/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RefreshTokenApi::class.java)
}
#Singleton
#Provides
fun provideHttpClient(headerInterceptor: HeaderInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addNetworkInterceptor(headerInterceptor)
.build()
}
#Singleton
#Provides
fun provideRetrofit(client: OkHttpClient): TwichApi {
return Retrofit.Builder()
.baseUrl("https://api.igdb.com/v4/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TwichApi::class.java)
}
}
class TwichHeaderRepository #Inject constructor(
private val refreshTokenApi: RefreshTokenApi)
{
suspend fun fetchRefreshToken(): Response<RefreshToken> {
return withContext(Dispatchers.IO) {
refreshTokenApi.getRefreshToken()
}
}
}
private const val TAG = "AddRepositoryAction"
private const val HEADER_CLIENT_ID = "Client-ID"
private const val HEADER_AUTHORIZATION = "Authorization"
private const val HEADER_ACCEPT = "Accept"
private const val DEFAULT_ACCESS_TOKEN = "mjycvndz4sasons2mg990kqme6vu6d"
private const val UNAUTHORIZED_STATUS_CODE = 401
#Singleton
class HeaderInterceptor #Inject constructor(
private val context: Context,
private val twichHeaderRepository: TwichHeaderRepository
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request().newBuilder().apply {
header(HEADER_CLIENT_ID, "i3nzc6w3n0pod39zgsq8h445o2yp6p")
header(HEADER_AUTHORIZATION, "Bearer $DEFAULT_ACCESS_TOKEN")
header(HEADER_ACCEPT, "application/json")
}.build())
val refreshToken = runBlocking { generateAccessToken(twichHeaderRepository) }
if (response.code == UNAUTHORIZED_STATUS_CODE) {
response.close()
val accessToken = ""
return chain.proceed(chain.request().newBuilder().apply {
header(HEADER_CLIENT_ID, "i3nzc6w3n0pod39zgsq8h445o2yp6p")
header(HEADER_AUTHORIZATION, "Bearer $accessToken")
header(HEADER_ACCEPT, "application/json")
}.build())
}
return response
}
}
private suspend fun generateAccessToken(twichHeaderRepository: TwichHeaderRepository): String
{
val responseRefreshToken = twichHeaderRepository.fetchRefreshToken()
return responseRefreshToken.body().toString()
}
interface RefreshTokenApi {
#POST(
...
)
suspend fun getRefreshToken(
): Response<RefreshToken>
}
#Singleton
#Component(modules = [AppModule::class])
interface AppComponent {
#Component.Factory
interface Factory {
fun create(#BindsInstance context: Context): AppComponent
}
fun inject(activity: MainActivity)
fun inject(fragment: AddFragment)
fun inject(interceptor: HeaderInterceptor)
}
class TwichRepository #Inject constructor(
private val twichApi: TwichApi
) {
suspend fun searchGames(title: String): Response<Game> {
return withContext(Dispatchers.IO) { twichApi.getGamesBySearch(title) }
}
}
Error message is
Found a dependency cycle okhttp3.OkHttpClient is injected at
com.example.glc.AppModule.provideRefreshTokenService(client)
com.example.glc.add.RefreshTokenApi is injected at
com.example.glc.add.TwichHeaderRepository(refreshTokenApi)
com.example.glc.add.TwichHeaderRepository is injected at
com.example.glc.add.HeaderInterceptor(�, twichHeaderRepository)
com.example.glc.add.HeaderInterceptor is injected at
com.example.glc.AppModule.provideHttpClient(headerInterceptor)
okhttp3.OkHttpClient is injected at
com.example.glc.AppModule.provideRetrofit(client)
com.example.glc.add.TwichApi is injected at
com.example.glc.add.TwichRepository(twichApi)
com.example.glc.add.TwichRepository is injected at
com.example.glc.add.AddViewModel(twichRepository)
com.example.glc.add.AddViewModel is injected at
com.example.glc.add.AddFragment.addViewModel
com.example.glc.add.AddFragment is injected at
com.example.glc.di.AppComponent.inject(com.example.glc.add.AddFragment)
You use Lazy on TwichHeaderRepository dependency in HeaderInterceptor's constructor to break the dependency cycle.
class HeaderInterceptor #Inject constructor(
private val lazyTwichHeaderRepository: Lazy<TwichHeaderRepository>
) {
// Access the dependency lazily with lazyTwichHeaderRepository.get()
}
I just needed to add #Named to resolve my problem and understand it as Mark said in the comment.
#Module
class AppModule {
#Singleton
#Provides
#Named("oauth2")
fun provideAccessTokenHttpClient() = OkHttpClient.Builder().build()
#Singleton
#Provides
fun provideRefreshTokenService(#Named("oauth2") client: OkHttpClient): RefreshTokenApi {
return Retrofit.Builder()
.baseUrl("https://id.twitch.tv/oauth2/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RefreshTokenApi::class.java)
}
#Singleton
#Provides
#Named("igdb")
fun provideSearchDataHttpClient(headerInterceptor: HeaderInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(headerInterceptor)
.build()
}
#Singleton
#Provides
fun provideRetrofit(#Named("igdb") client: OkHttpClient): TwichApi {
return Retrofit.Builder()
.baseUrl("https://api.igdb.com/v4/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TwichApi::class.java)
}
}
I am trying to implement multiple instance of retrofit for two different base URL`s using Dagger2 and MVVM. I have already wasted a huge amount of time testing different approaches provided here in SO, but still unable to figure it out. I have created new Qualifiers as well and created a new instance but all my request are still made using first instance.Here is my implementation.
Qualifiers
#Retention(AnnotationRetention.BINARY)
#Qualifier
annotation class APIService1
#Retention(AnnotationRetention.BINARY)
#Qualifier
annotation class APIService2
AppModule class
#AssistedModule
#Suppress("unused")
#Module(includes = [ViewModelModule::class, CoreDataModule::class, AssistedViewModelModule::class, AssistedInject_AppModule::class])
class AppModule {
#Singleton
#Provides
fun provideServices(
APIService1 okHttpClient: OkHttpClient, converterFactory: MoshiConverterFactory
) =
provideService(okHttpClient, converterFactory, MyApi::class.java)
#Singleton
#Provides
#APIService2
fun provideMicroServices(
APIService1 okHttpClient: OkHttpClient, converterFactory: MoshiConverterFactory
) =
provideMicroService(okHttpClient, converterFactory, MyApi::class.java)
#APIService1
#Provides
fun providePrivateOkHttpClient(upstreamClient: OkHttpClient): OkHttpClient {
return upstreamClient.newBuilder().build()
}
#Singleton
#Provides
fun provideRemoteDataSource(myApiService: MyApi) = RemoteDataSource(myApiService)
private fun createRetrofit(
okhttpClient: OkHttpClient,
converterFactory: MoshiConverterFactory
): Retrofit {
Retrofit.Builder()
.baseUrl("https://example1.com/api/")
.client(okhttpClient)
.addConverterFactory(converterFactory)
.build()
}
private fun createMicroServiceRetrofit(
okhttpClient: OkHttpClient,
converterFactory: MoshiConverterFactory
): Retrofit {
Retrofit.Builder()
.baseUrl("https://example2.com/api/")
.client(okhttpClient)
.addConverterFactory(converterFactory)
.build()
}
private fun <T> provideService(
okhttpClient: OkHttpClient,
converterFactory: MoshiConverterFactory, clazz: Class<T>
): T {
return createRetrofit(okhttpClient, converterFactory).create(clazz)
}
private fun <T> provideMicroService(
okhttpClient: OkHttpClient,
converterFactory: MoshiConverterFactory, clazz: Class<T>
): T {
return createMicroServiceRetrofit(okhttpClient, converterFactory).create(clazz)
}
}
CoreDataModule class
#Module
class CoreDataModule {
#Provides
fun provideOkHttpClient(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient().newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(90, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
return client.build()
}
#Provides
#Singleton
fun provideMoshi(): Moshi = Moshi.Builder().build()
#Provides
#Singleton
fun provideMoshiConverterFactory(): MoshiConverterFactory =
MoshiConverterFactory.create()
}
RemoteDataSource Class
#Keep
class RemoteDataSource #Inject constructor(private val service: MyApi) : BaseDataSource() {
suspend fun getOtp(data: String) = getResult { service.getOtp(data) }
suspend fun getData(data: String) = getResult { service.getData(data) }
}
BaseDataSource Class
abstract class BaseDataSource {
protected suspend fun <T> getResult(call: suspend () -> Response<T>): Result<T> {
val response = call()
if (response.isSuccessful) {
val body = response.body()
if (body != null) return Result.success(body)
}
return error(" ${response.code()} ${response.message()}")
}
}
MyApi Class
interface MyApi {
#POST("Register/Otp")
#FormUrlEncoded
suspend fun getOtp(#Field("data") data: String): Response<OtpResponse>
#POST("Home/Data")
#FormUrlEncoded
suspend fun getData(#Field("data") data: String): Response<DataResponse>
}
This is how i am using it in my ViewModel
One of My ViewModles
class OtpViewModel #Inject constructor(
private val remoteDataSource: RemoteDataSource
) :
ViewModel() {
fun getNewOtp() = liveData {
try {
emit(Resource.loading(data = null))
val response = remoteDataSource.getOtp(params))
emit(Resource.success(data = response))
} catch (e: Exception) {
emit(Resource.error(data = null, message = e.message ?: e.localizedMessage.orEmpty()))
}
}
Create 2 annotations like this:
#Qualifier
#Target(
AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD,
AnnotationTarget.VALUE_PARAMETER
)
#Retention(AnnotationRetention.BINARY)
annotation class ApiService1
#Qualifier
#Target(
AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD,
AnnotationTarget.VALUE_PARAMETER
)
#Retention(AnnotationRetention.BINARY)
annotation class ApiService2
Change your providers with:
#Provides
#Singleton
#ApiService1
fun provideServices(....): MyApi {
return ...
}
#Provides
#Singleton
#ApiService2
fun provideMicroServices(....): MyApi {
return ...
}
Then in your Android classes you can do this:
class MyActivity : FragmentActivity() {
#Inject
#ApiService1
lateinit var retrofit1: MyApi
#Inject
#ApiService2
lateinit var retrofit2: MyApi
....
}
Or in classes:
class Repository #Inject constructor (
#ApiService1 retrofit1: MyApi
) {
....
}
I have problem using dagger 2 for updating token in runtime.
So here is the scenario:
I have a screen to Change Password. when i succeed update password, the current jwt token would be invalid, and i need to store new token from update token response, i store that token in SharedPreferences. but the problem is when i store the token. it updated in sharedprefernces, but wont update value in DaggerGraph where i build Retrofit instance (Authorization header).
Below is my code :
AppComponent.kt
#Singleton
#Component(
modules = [StorageModule::class, AppModule::class, ViewModelModule::class]
)
interface AppComponent {
#Component.Factory
interface Factory {
fun create(#BindsInstance context: Context): AppComponent
}
fun inject(activity: SplashActivity)
fun inject(activity: LoginActivity)
fun inject(activity: MainActivity)
fun inject(activity: ChangePasswordActivity)
}
AppModule.kt
#Module
class AppModule {
#Singleton
#Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(sharedPreferencesSources.tokenApi())
}
#Singleton
#Provides
fun provideApiService(
authInterceptor: Interceptor
): SharedProductClient {
return Network.retrofitClient(authInterceptor = authInterceptor)
.create(SharedProductClient::class.java)
}
#Singleton
#Provides
fun provideAppRepository(apiService: SharedProductClient): AppRepository {
return AppRepositoryImpl(apiService)
}
#Singleton
#Provides
fun provideAppUseCase(appRepository: AppRepository): AppUseCase {
return AppUseCase(appRepository)
}
#Singleton
#Provides
fun provideAppScheduler(): SchedulerProvider = AppSchedulerProvider()
}
StorageModule.kt
#Module
class StorageModule {
#Singleton
#Provides
fun provideSharedPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(SharedPrefName, Context.MODE_PRIVATE)
}
#Singleton
#Provides
fun provideSharedPreferencesSource(sharedPrefInstance: SharedPreferences): SharedPreferencesSources {
return SharedPreferencesSourcesImpl(sharedPrefInstance)
}
companion object {
const val SharedPrefName = "share_product_prefs"
}
}
AuthInterceptor.kt
class AuthInterceptor constructor(
private val token: String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer $token")
.build()
)
}
}
Any suggestion would be really help me. Thanks!
This is because you only pass a String instance of the token when creating the AuthInterceptor.
You should provide a way (e.g. an interface) of dynamically obtaining the token from the SharedPreferences when needed.
This is one way of doing this:
Change the token:String to a function type in your AuthInterceptor constructor (and use it when needed):
class AuthInterceptor constructor(
private val tokenProvider: () -> String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer ${tokenProvider.invoke()}")
.build()
)
}
}
When creating your AuthInteceptor build your lambda to dynamically refer to SharedPreferences
#Module
class AppModule {
#Singleton
#Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(){ sharedPreferencesSources.tokenApi() }
}
//...
}
This way the tokenProvider will be invoked (SharedPreferences will be accessed) every time you make an api call, instead of just a single time when creating the AuthInterceptor.
I decided to add clean architecture to my project, I added three separate modules to the project: domain, data, presentation (app) and I divided the code into thees three modules. After that, I had a problem with Dagger, when I try to build the application, it says that it cannot access the WeatherDataApiService (this is the interface in which I make an API request using the retrofit library) I transferred this interface to the data module. In general, the problem is that I do not understand how to properly organize dependency injection so that classes have access to each other. The problem is that when Dagger is being built, access to the data module is closed. The problem is that I need to correctly distribute the dependencies between the modules. At the moment, my dependencies between the modules are built in this way - presentation(app) depends on the domain module, and the domain module depends on the data module
This is the interface WeatherDataApiService
interface WeatherDataApiService {
#GET("/v2.0/forecast/daily")
fun getWeatherData(
#Query("city") city: String,
#Query("days") days: Int,
#Query("units") degreeType: String
):Single<WeatherDataApiModel>
companion object {
operator fun invoke(): WeatherDataApiService {
val key = "40a7956799be42f49bc8b6ac4bb8e432"
val requestInterceptor = Interceptor{chain->
val url = chain.request()
.url() // HttpUrl
.newBuilder() // HttpUrl.Builder
.addQueryParameter("key", key) // HttpUrl.Builder
.build()
val request = chain.request()
.newBuilder() // Request.Builder
.url(url) // Request.Builder
.build() // Request
return#Interceptor chain.proceed(request) // Response
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor) // OkHttpClient.Builder()
.build()
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://api.weatherbit.io")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
.create(WeatherDataApiService::class.java)
}
}
}
This is the repository located in the domain module.
class WeatherDataRepositoryImpl #Inject constructor(
private val weatherDataApiService : WeatherDataApiService,
private val mapper : WeatherDataMapper
) : WeatherDataRepository {
override fun getWeatherData(
city: String,
days: Int,
degreeType: String
): Single<WeatherData> =
weatherDataApiService.getWeatherData(city, days, degreeType)
.map { mapper.mapWeather(it) }
}
This is the use case code where I use the repository
class FetchWeatherDataUseCase #Inject constructor(private val weatherDataRepository: WeatherDataRepository) {
fun fetchWeatherData(city: String,days: Int,degreeType: String): Single<WeatherData> {
return weatherDataRepository.getWeatherData(city,days,degreeType)
}
}
This is the code of the Dagger module which is in domain
#Module
class WeatherDataRepositoryModule {
#Provides
#Singleton
fun providerWeatherDataRepository(
mapper: WeatherDataMapper,
weatherDataApiService: WeatherDataApiService
): WeatherDataRepository =
WeatherDataRepositoryImpl(
weatherDataApiService,
mapper
)
#Provides
#Singleton
fun providerApiService() = WeatherDataApiService()
#Provides
fun providerMapper() = WeatherDataMapper()
}
This is the code of the Dagger module which is in presentation(app)
#Module
class WeatherDataModule {
#Provides
#Singleton
fun provideFetchWeatherDataUseCase(weatherDataRepository: WeatherDataRepository) =
FetchWeatherDataUseCase(weatherDataRepository)
}
This is the code of the Dagger Component which is in presentation(app)
#Singleton
#Component(modules = [WeatherDataModule::class, WeatherDataRepositoryModule::class])
interface WeatherDataComponent {
fun injectWeatherDataFragment(weatherDataFragment: WeatherDataFragment)
}
Here I am creating a dagger, the code is in presentation (app)
class App : Application() {
lateinit var weatherDataComponent: WeatherDataComponent
override fun onCreate() {
super.onCreate()
weatherDataComponent = DaggerWeatherDataComponent.create()
}
}
Error text - cannot access WeatherDataApiService