내일은개발왕

[안드로이드 스튜디오] - Hilt구요 저도 에러를 낼거에요 ㅎㅎ - @Qualifier retrofit 사용시 본문

오류삽질,기타삽질

[안드로이드 스튜디오] - Hilt구요 저도 에러를 낼거에요 ㅎㅎ - @Qualifier retrofit 사용시

NDN 2024. 5. 24. 23:15

캡스톤 서버에서 JWT 토큰을 사용한다.

근데 로그인 회원가입 부분은 JWT 토큰이 필요없고, 로그인시에 이를 발급해주니 제외하라고 말하더라..

Okay 하고 코드 분리시키는데, 아름다운 에러가 났다.

error: [Dagger/MissingBinding] com.example.callphobia_overs.main.network.api.RingApi cannot be provided without an @Provides-annotated method.
  public abstract static class SingletonC implements Application_GeneratedInjector,
                         ^
  
  Missing binding usage:
      com.example.callphobia_overs.main.network.api.RingApi is injected at
          com.example.callphobia_overs.main.network.api.Repository(api, ��)
      com.example.callphobia_overs.main.network.api.Repository is injected at
          com.example.callphobia_overs.main.network.viewmodel.DataViewModel(repository, ��)
      com.example.callphobia_overs.main.network.viewmodel.DataViewModel is injected at
          com.example.callphobia_overs.main.network.viewmodel.DataViewModel_HiltModules.BindsModule.binds(vm)
      @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.callphobia_overs.main.core.Application_HiltComponents.SingletonC �� com.example.callphobia_overs.main.core.Application_HiltComponents.ActivityRetainedC �� com.example.callphobia_overs.main.core.Application_HiltComponents.ViewModelC]
  It is also requested at:
      com.example.callphobia_overs.main.network.api.Repository(api, ��)
  The following other entry points also depend on it:
      com.example.callphobia_overs.main.view.home.HomeFragment_GeneratedInjector.injectHomeFragment(com.example.callphobia_overs.main.view.home.HomeFragment) [com.example.callphobia_overs.main.core.Application_HiltComponents.SingletonC �� com.example.callphobia_overs.main.core.Application_HiltComponents.ActivityRetainedC �� com.example.callphobia_overs.main.core.Application_HiltComponents.ActivityC �� com.example.callphobia_overs.main.core.Application_HiltComponents.FragmentC]
C:\Users\Home\Desktop\CallPhobia_OverS\app\build\generated\hilt\component_sources\debug\com\example\callphobia_overs\main\core\Application_HiltComponents.java:139: error: [Dagger/MissingBinding] com.example.callphobia_overs.main.network.api.RingInterceptorApi cannot be provided without an @Provides-annotated method.
  public abstract static class SingletonC implements Application_GeneratedInjector,
                         ^

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이러지마제발

딱 보자마자 아니 씨 이건 또 뭔에러야 하고 한시간 동안 삽질했는데 여러분은 그러지마시길 바라며... 

Hilt에 대해서도 더 공부해야겠다.. ㅠㅠ 


JWT 토큰 사용하는 retrofit, 아닌 retrofit을 만들 때 같은 baseurl을 사용하고 있다면 @Qualifier를 사용한다.

즉, 이름을 구분지어 필요한 통신객체를 부른다는 것이다. 안그럼 "아니 retrofit 객체 둘 중 뭘사용하라는거야?"라며 오류가 난다. 그래서 분리를 시켜줬다. 아래는 retrofitModule 코드다.

@Module
@InstallIn(SingletonComponent::class)
object retrofitModel {
 private val logging = HttpLoggingInterceptor().apply{
        level = HttpLoggingInterceptor.Level.BODY //okhttp 로그 추가
    }

    /** JWTToken이 필요한 api와, 그렇지 않은 api 연결을 위해
     * Qualifier를 사용해 구분짓기 위한 annotation 클래스 생성*/
    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class InterceptorOkHttpClient

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class NoInterceptorOkHttpClient

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class NoInterceptorRetrofit

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class InterceptorRetrofit

    /** OkHTTP에 각 annotaion을 붙여주어 구분짓도록 하기 */
    @NoInterceptorOkHttpClient
    @Singleton
    @Provides
    fun OkHttpClient() : OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(logging)
            .build()
    }

    @InterceptorOkHttpClient
    @Singleton
    @Provides
    fun OkHttpClientInterceptor() : OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(logging)
            .build()
    }

    @NoInterceptorRetrofit
    @Singleton
    @Provides
    fun ringRetrofit(@NoInterceptorOkHttpClient client: OkHttpClient) : RingApi {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .baseUrl(baseUrl)
            .build()
            .create(RingApi::class.java)
    }

    @InterceptorRetrofit
    @Singleton
    @Provides
    fun ringInterceptorRetrofit(@InterceptorOkHttpClient client: OkHttpClient) : RingInterceptorApi {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .baseUrl(baseUrl)
            .build()
            .create(RingInterceptorApi::class.java)
    }

}

Hilt를 사용해 싱글톤으로 retrofit을 만들어 주었으니, 이제 만들어둔 api 인터페이스 가지고 연결지으면 되는데....

여기서 문제가 난다.

class Repository @Inject constructor(private val api : RingApi, //문제의
                                     private val interceptorApi: RingInterceptorApi,//원인들
                                     private val callDao: CallRecordsDao) {

바로이부분!!!!!!!!!!!!!!! 저거 위에 저거!!!!!!!!!!! api 사용하는 저부분!!!!!

retrofit 객체 두개 다 분리 잘 시켜두고, 막상 repository에서 사용할 때 어떤 retrofit 객체를 사용해서 통신할건지를 명시 안해줬었던거다.... ㅎ... 

class Repository @Inject constructor(@retrofitModel.NoInterceptorRetrofit private val api : RingApi,
                                     @retrofitModel.InterceptorRetrofit private val interceptorApi: RingInterceptorApi,
                                     private val callDao: CallRecordsDao) {

이렇게 수정하면 정말 빌드가 잘 된다...

그리고 @retrofitModel.. 이렇게 적으면 자동완성 안된다. 대신, 만들어두었던 @Qualifier를 먼저 작성해주면 된다.

즉, @NoInterce..... 이렇게 적으면 바로 자동완성 떠서 사용할 수 있다.

이러면 빌드가 잘 되는것을 볼 수 있다. 😆👍


처음으로 분리시켜보는거라 자료를 뒤져봤는데 아래 블로그분을 참고해 코드를 작성했었다.

자료 남겨주셔서 정말 감사합니다 (__)

https://velog.io/@galaxy/Hilt-Qualifier

 

Hilt - @Qualifier

DI 라이브러리인 Hilt 의 @Qualifier 에 대해 정리했습니다.

velog.io