마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

hilt로 retrofit 만드는 클래스 생성자에 주입

0 추천

기존의 retorift builder를 만들고 인터셉터등 세팅하는걸 담당하는 클래스에서

생성자로 boolean 값을 받아 분기처리를 하는 코드인데요

이거를 hilt를 적용해서 해보려니 이 생성자로 boolean 값을 어떻게 주입해야될지를 모르겠습니다.

@Module
@InstallIn(SingletonComponent::class)
class ModuleApiManager @Inject constructor(private val m_bNeedToken : Boolean){
    @Singleton
    @Provides
    fun provideApiManager() : ApiService{
        var sUeserAgent = BasePreference.getInstance()[CommonInfo.USER_AGENT_KEY]
        var sLoginToken = ""
        var okHttp : OkHttpClient

        if (m_bNeedToken) {
            // 처리하는 코드
        }

해당 코드구요 

m_bNeedToken t/f에 따라 처리하는 코드가 있습니다 저렇게 주입을 받겠다는 코드까진 넣었는데

저걸 ModuleApiManager(t/f) 이렇게 넣어줄수도 없는 노릇이고 어떻게 주입을 해야되나요

수원통학러 (3,570 포인트) 님이 2023년 3월 14일 질문

1개의 답변

0 추천

하고 싶은신게 로그인을 한 경우라면 access token을 헤더에 추가해 주고 싶은신 거 같은데요. 이런 경우는 상황에 따라 처리를 해야 하는데, access token의 존재여부(m_bNeedToken)는 런타임에 결정되기 때문에, 님이 하신 것 처럼 singleton을 클래스를 만들어 해당 조건을 주입해서 사용할 수가 없습니다.

이런 경우는 OkHttp의 Interceptor를 사용해서 처리하실 수 있습니다.

class AccessTokenInterceptor @Inject constructor(
    private val preferences: BasePreferences
) : Interceptor {

    companion object {
        private const val AUTHORIZATION = "authorization"
        private const val BEARER_PREFIX = "Bearer"
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        val accessToken = preferences.accessToken
        if (accessToken.isBlank()) {
            return chain.proceed(request)
        }

        val newRequest = request.newBuilder()
            .addHeader(AUTHORIZATION, "$BEARER_PREFIX $accessToken")
            .build()
        return chain.proceed(newRequest)
    }
}

fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
                    .addInterceptor(AccessTokenInterceptor())
                    .build()
    }

 

spark (224,800 포인트) 님이 2023년 3월 14일 답변
로그인상태에 따른건 맞습니다
Api마다 비로그인이어도 가능한 api와 로그인이 되어있는경우에만 호출가능한 api가 있어서
힐트적용전 코드는 매니저클래스의 생성자로 mNeedtoken를 t f 받아
T인경우 토큰가져와서 인터셉터에 담아보내고 있구요 f인경우 공백으로 넣어 보내는 형태입니다 해당 인터셉터는 그 담은걸 또 가공하는 형태라 그래서 단순히 bool값만 어떻게 넘겨주면겨줄 방법은 없는걸까요?
primitive 탑을 inject하는건 별로 권장하지 않는 방식입니다. 굳이 하려면  Qualifier같은 걸로 구분하시는게 좋구요. 직접 해당 값은 inject하기 보다는 해당값을 제공할 수 있는 오브젝트같을 걸  inect하시면 됩니다.

interface SessionManager {
    fun isLoggedIn(): Boolean
    fun accessToken(): String
}

@Module
@InstallIn(SingletonComponent::class)
class ModuleApiManager @Inject constructor(
    private val sessionManager : SessionManager
){
    @Singleton
    @Provides
    fun provideApiManager() : ApiService{
        var sUeserAgent = BasePreference.getInstance()[CommonInfo.USER_AGENT_KEY]
        var okHttp : OkHttpClient

        if (sessionManager.isLoggedIn()) {
            // 처리하는 코드
            var sLoginToken = sessionManager.accessToken()
        }
}

그런데 재미있는 것은, 위의 코드가 결국은 제가 보여드린 interceptor와 같게 된다는 겁니다. 제가 볼 때 토큰을 헤더에 추가하는 것은 세션상태를 체크해서 토큰을 헤더에 추가하는 interceptor의 역할입니다. 따라서 님의 코드에 AccessTokenInterceptor를 inject해서 사용하는게 더 쉬울 것 같다는 생각이 들기도 하네요. 그게 DI의 개념과도 더 부합하구요.
...