Thread
#dagger
    Hovhannes

    Hovhannes

    1 year ago
    Hello, I get this error. What is the reason? " error: @Binds methods' parameter type must be assignable to the return type public abstract com.example.data.network.AuthApi " in AppModule
    @Module
    @InstallIn(SingletonComponent::class)
    abstract class AppModule {
    
    
        companion object {
            @Singleton
            @Provides
            fun provideRemoteDataSource(): RemoteDataSource {
                return RemoteDataSource()
            }
    
    
    
            @Singleton
            @Provides
            fun provideUserApi(
                remoteDataSource: RemoteDataSource,
          
            ): UserApi {
                return remoteDataSource.buildTokenApi()
            }
    
            @Provides
            fun provideAuthRepository(authApi: AuthApi): AuthRepository {
                return AuthRepository(authApi)
            }
    
    
            @Provides
            fun provideUserRepository(userApi: UserApi): UserRepository {
                return UserRepository(userApi)
            }
        }
    
    
    
            @Binds
            @Singleton
            abstract fun bindsRemoteDataSource(authRepository: AuthRepository): AuthApi
    }
    class AuthRepository @Inject constructor(private val api: AuthApi) : BaseRepository(api) {....}
    a

    Arun

    1 year ago
    params of the
    @binds
    should be a subclass of the method return type is
    AuthRepository
    subclass of
    AuthApi
    ?
    @Binds
            @Singleton
            abstract fun bindsRemoteDataSource(authRepository: AuthRepository): AuthApi
    Hovhannes

    Hovhannes

    1 year ago
    @Arun thanks for your reply. No 
    AuthRepository
     is not subclass of 
    AuthApi
    . I can show Authapi.
    interface AuthApi : BaseApi {
    
        @FormUrlEncoded
        @PUT("{PartnerId}/LoginClient")
        suspend fun login(
            @Field("name") name:String,
            @Path("partnerId") partnerId:String,
            @Field("Password") password: String
        ): LoginResponse
    }
    a

    Arun

    1 year ago
    That is the issue. By writing
    bindsRemoteDataSource(authRepository: AuthRepository): AuthApi
    you are asking dagger to bind
    AuthApi
    interface to
    authRepository
    which is an invalid connection. Did you mean to bind
    AuthApi
    instead? I assume this is for Retrofit, instead what you can do is to write a @Provides method similar to ones you have already written and return the instance created with Retrofit builder for example like this
    @Provides fun authApi() {
      Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("<https://api.github.com/>")
        .build();
    
     return retrofit.create(AuthApi.class);
    }
    Hovhannes

    Hovhannes

    1 year ago
    @Arun I want to say that if I don't use the @Binds method, I get this error "AuthApi cannot be provided without an @Provides-annotated method". So why I use the @Binds method
    a

    Arun

    1 year ago
    That is correct, @Binds can be used only when the instance to be bound is already available i.e dagger knows how to create an instance of class you want to inject. In this, Dagger can't know how to instantiate the class and Retrofit is the one that can correct implementation of AuthApi. Hence instead of using @Binds, you need to use @Provides since @Provides allows you manually create the instance instead of dagger attempting to create it.
    AuthApi cannot be provided without an @Provides-annotated method
    Dagger is basically saying it can't create instance of AuthApi and neither there is a @Provides method to help create one.
    Hovhannes

    Hovhannes

    1 year ago
    @Arun what do you offer for fixing the issue? I can't use the below code, because url is not constant, it changes every time.
    @Provides fun authApi() {
      Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("<https://api.github.com/>")
        .build();
    
     return retrofit.create(AuthApi.class);
    }
    a

    Arun

    1 year ago
    In that case you would need to make the url configurable by
    @Provides fun authApi(@Named("baseUrl") baseUrl : String) {
      Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(baseUrl)
        .build();
    
     return retrofit.create(AuthApi.class);
    }
    Then create another binding for baseUrl like done here https://github.com/chrisbanes/tivi/blob/main/app/src/main/java/app/tivi/inject/AppModule.kt#L76 Will the API url change at runtime? If so you can return a retrofit builder instead and build api instance at runtime like
    @Provides fun retrofitBuilder() : Retrofit.Builder() {
     return  Retrofit.Builder().apply {
       // any other config
     }
    }
    
    ///
    class AuthRepository @Inject constructor(private val apiBuilder: Retrofit.Builder) : BaseRepository {
       private val authApi by lazy {
         
         apiBuilder.baseUrl("<url here>").build()
       }
    }
    Hovhannes

    Hovhannes

    1 year ago
    @Arun I want to say that buildApi() was in RemoteDataSource. But now I want to move buildApi() to a fragment, because I need to pass a data as buildApi()'s parameter. I do it, because I haven't fix this issue till now https://kotlinlang.slack.com/archives/C0B8M7BUY/p1629201848365200