Android에서 Retrofit을 사용한 HTTP 통신 방법을 알아봅니다.

Dependencies

implementation "com.squareup.retrofit2:retrofit:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.4.0"

Retrofit Builder

기본 설정

object Api {
    val service by lazy {
        val gson = GsonBuilder()
            .setLenient()
            .create()

        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
            .create(ApiService::class.java)
    }
}

상세 설정

class APIClient {
    private var retrofit: Retrofit? = null

    enum class LogLevel {
        LOG_NOT_NEEDED,
        LOG_REQ_RES,
        LOG_REQ_RES_BODY_HEADERS,
        LOG_REQ_RES_HEADERS_ONLY
    }

    fun getClient(logLevel: LogLevel): Retrofit {
        val interceptor = HttpLoggingInterceptor()
        when (logLevel) {
            LogLevel.LOG_NOT_NEEDED ->
                interceptor.level = HttpLoggingInterceptor.Level.NONE
            LogLevel.LOG_REQ_RES ->
                interceptor.level = HttpLoggingInterceptor.Level.BASIC
            LogLevel.LOG_REQ_RES_BODY_HEADERS ->
                interceptor.level = HttpLoggingInterceptor.Level.BODY
            LogLevel.LOG_REQ_RES_HEADERS_ONLY ->
                interceptor.level = HttpLoggingInterceptor.Level.HEADERS
        }

        val client = OkHttpClient.Builder()
            .connectTimeout(3, TimeUnit.MINUTES)
            .writeTimeout(3, TimeUnit.MINUTES)
            .readTimeout(3, TimeUnit.MINUTES)
            .addInterceptor(interceptor)
            .build()

        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                .baseUrl(Constants.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build()
        }

        return retrofit!!
    }

    fun getAPIService(logLevel: LogLevel = LogLevel.LOG_REQ_RES_BODY_HEADERS) =
        getClient(logLevel).create(APIService::class.java)
}

Service Interface

기본 형태

interface ApiService {
    @POST("endpoint/path")
    fun postData(@Body body: RequestBody): Call<ResponseType>

    @GET("endpoint/path")
    fun getData(@Query("param") param: String): Call<ResponseType>
}

RxJava와 함께 사용

interface ApiService {
    @POST("todos/list")
    fun getToDoList(): Observable<GetToDoListResponse>

    @POST("todos/edit")
    fun editTodo(@Body todo: String): Observable<BaseResponse>

    @POST("todos/add")
    fun addTodo(@Body todo: String): Observable<BaseResponse>
}

RxJava Adapter 추가:

Retrofit.Builder()
    .baseUrl(Constants.BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

API 호출

Callback 방식

Api.service.getData(param).enqueue(object : Callback<ResponseType> {
    override fun onFailure(call: Call<ResponseType>?, t: Throwable?) {
        println("Error: $t")
    }

    override fun onResponse(call: Call<ResponseType>?, response: Response<ResponseType>?) {
        println("Response: ${response?.body()}")
    }
})

RxJava 방식

APIClient()
    .getAPIService()
    .getToDoList()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeBy(
        onNext = { response ->
            adapter.setDataset(response.data)
        },
        onError = { e ->
            e.printStackTrace()
        }
    )

Thread 설정

특정 스레드에서 응답을 받으려면:

Retrofit.Builder()
    .baseUrl(Constants.BASE_URL)
    .callbackExecutor(Executors.newSingleThreadExecutor())
    .build()

ProGuard 설정

Retrofit 사용 시 ProGuard 설정이 필요합니다:

공식 문서에서 최신 ProGuard 규칙을 확인하세요.

구조 가이드

ApiClient

모든 서비스를 포함합니다.

Service

모든 API 엔드포인트를 포함합니다.

// 구조 예시
ApiClient
 ├── UserService
     ├── login()
     ├── logout()
     └── getProfile()
 └── TodoService
      ├── getList()
      ├── add()
      └── edit()