Hello, I get this error. What is the reason? " error: @Binds methods' parameter type must be assign...
h
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
Copy code
@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
}
Copy code
class AuthRepository @Inject constructor(private val api: AuthApi) : BaseRepository(api) {....}
a
params of the
@binds
should be a subclass of the method return type is
AuthRepository
subclass of
AuthApi
?
Copy code
@Binds
        @Singleton
        abstract fun bindsRemoteDataSource(authRepository: AuthRepository): AuthApi
h
@Arun thanks for your reply. No 
AuthRepository
 is not subclass of 
AuthApi
. I can show Authapi.
Copy code
interface AuthApi : BaseApi {

    @FormUrlEncoded
    @PUT("{PartnerId}/LoginClient")
    suspend fun login(
        @Field("name") name:String,
        @Path("partnerId") partnerId:String,
        @Field("Password") password: String
    ): LoginResponse
}
a
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
Copy code
@Provides fun authApi() {
  Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("<https://api.github.com/>")
    .build();

 return retrofit.create(AuthApi.class);
}
h
@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
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.
h
@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.
Copy code
@Provides fun authApi() {
  Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("<https://api.github.com/>")
    .build();

 return retrofit.create(AuthApi.class);
}
a
In that case you would need to make the url configurable by
Copy code
@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
Copy code
@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()
   }
}
h
@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
1089 Views