본문 바로가기
Android/Retrofit

[Android] okHttp vs Retrofit

by 태크민 2023. 9. 13.

OkHttp vs Retrofit

둘 다 같은 회사(Square)에서 만든 HTTP 통신 라이브러리이다. OkHttp는 REST API, HTTP 통신을 간편하게 구현할 수 있도록 여러가지 기능을 제공한다. 그리고 이러한 OkHttp를 기반으로 Type-safe하고, 더 직관적으로 사용할 수 있도록 인터페이스로 만들어진 게 Retrofit이다. 따라서 완전히 다르진 않지만, 지원 기능과 용도 면에서 어느정도 차이가 있다.

Retrofit이 OkHttp보다 Type-safe한 이유?
: 개발자가 Json의 Raw한 문자열을 잘못 파싱할 수도 있는 문제를 줄여준다. 또한, 직접 파싱할 필요가 없기 때문에 코드가 간결해지고 편리하다는 장점까지 있다.

 

다음과 같은 장점의 이유로 OkHttp보다 Retrofit이 더 많이 쓰이고 있다.

1. 어노테이션의 사용

먼저 Retrofit부터 확인해보자. Retrofit에선 BASE URL을 인자로 전달하여 간단하게 객체를 생성한다.

Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl(BASE_URL)
    .build()

다음으로 인터페이스를 생성하고, 원하는 요청 방식과 파라미터에 대해 정의한다.

  interface wikiApiServe{
      @GET(END_POINT)
      fun hitCountCheckCall(
          @Query(PARAM_ACTION) action: String,
          @Query(PARAM_FORMAT) format: String,
          @Query(PARAM_LIST) list: String,
          @Query(PARAM_SRSEARCH) srsearch: String)
      : Call<Model.Result>
  }

이후 네트워크 호출을 할 때마다 미리 정의해놓은 인터페이스 메서드에 필요한 데이터들을 전달해서 호출할 수 있다.

  wikiApiServe.hitCountCheckCall(
          VALUE_QUERY, VALUE_JSON, VALUE_SEARCH, searchString)

반면 OkHttp에선 다음과 같이 수동으로 요청을 구성해야 한다. 물론 한다면 할 수야 있지만 URL을 입력하는 과정에서 오타가 날 수도 있고, 무엇보다 가독성 면에서 좋지 못하다.

  val request = Request.Builder().url("$BASE_URL$BASE_PATH/?" +
        "$PARAM_ACTION=$VALUE_QUERY&$PARAM_FORMAT=$VALUE_JSON&" +
        "$PARAM_LIST=$VALUE_SEARCH&$PARAM_SRSEARCH=$searchString")
        .build()

 

2. 편리한 Interface 제공

또한, Retrofit은 Call을 반환해주는 Interface를 통해, 직관적이고 간편하게 개발할 수 있도록 도와준다.

interface ProductService {
    @GET("/products")
    fun getProducts(): Call<List<Product>>
}

하지만 OkHttp에서는 OkHttpClient.newCall(request) 메서드를 호출하여 call을 만들어주어야 하기 때문에, 매번 Request를 만들어주는 작업이 필요하다. Retrofit은 이런 작업을 생략해줄 수 있을 뿐만아니라 Annotation(GET, POST, PATCH 등)을 지정해주어 훨씬 직관적이다.

val okHttpClient = OkHttpClient.Builder() // 1.
    .addInterceptor(...)
    .build()
            
val productJson = Gson().toJson(Product(1, "과자")) // 2.

// 서버에 POST 하기 위한 Request Body
// Json 형태의 String을 RequestBody로 변환
val requestBody = productJson.toRequestBody("application/json".toMediaType()) // 3.

// 요청을 위한 Request
val request = Request.Builder().run { // 4.
    url("https://localhost:8080/products")
    header("Authorization", "Basic {token}")
    post(requestBody)
    build()
}

okHttpClient.newCall(request).enqueue(object : Callback { // 5.
    override fun onFailure(call: Call, e: IOException) {
        // Handle this
    }

    override fun onResponse(call: Call, response: Response) {
        val jsonObject = JSONObject(response.body?.string() ?: "{}") // 6.
        runOnUiThread {
            ... // Ui Logic
        }
    }
})

 

3. Json <-> Object 자동 변환

다음으로 네트워크 통신 시, 반환되는 응답 객체에 대해 두 라이브러리 간 어떤 차이가 있는지 알아보자. 알다시피 JSON은 자바나 코틀린에서 바로 사용할 수 있는 데이터 형식이 아니기 때문에 JSON을 데이터 클래스로 변환해줄 컨버터를 사용해야 한다. 객체 생성 시 GSON Converter Factory를 연결했다면, Retrofit은 통신 성공 시 응답 객체의 body를 별도의 변환 과정 없이 사용할 수 있다.

call?.enqueue(
  object : Callback<Model.Result> {
    override fun onFailure(call: Call<Model.Result>, t: Throwable) {
          ...
    }

    override fun onResponse(call: Call<Model.Result>, 
    	response: Response<Model.Result>) {
          	response.body()?.let { //바로 사용 가능 }
    }

 

반면 OkHttp에서는 반환받은 JSON 객체를 데이터 클래스로 바로 변환해주지 못하기 때문에, 별도의 과정을 통해 직접 변환해서 사용해야 한다.

client.newCall(request).enqueue(
  object : okhttp3.Callback {
    override fun onFailure(call: okhttp3.Call, e: IOException) {
         ...
    }

    override fun onResponse(call: okhttp3.Call, 
          response: okhttp3.Response) {
            response.body()?.let { 
               val result = Gson().fromJson(it.string(), 
                            Model.Result::class.java)
               useResult(result) 
            }
        }
)

 

4. 자동으로 UI 스레드 수행 지원

또한 결과가 반환된 직후 메인스레드에서 바로 사용할 수 있냐 없냐에도 차이가 있다. Retrofit의 경우 enqueue를 사용하면 네트워크 호출이 자동으로 백그라운드에서 이루어진다. 그리고 결과가 반환되면 자동으로 메인스레드에 전달되기 때문에 Toast와 같은 UI 관련 메서드에 결과값을 사용할 수 있다.

override fun onResponse(call: Call<Model.Result>, 
                 response: Response<Model.Result>) {
          Toast.makeText(...).show()
    })

OkHttp도 enqueue를 사용하면 네트워크 호출이 자동으로 백그라운드에서 수행되지만, 결과가 반환되어도 여전히 백그라운드에 남아있기 때문에 결과값을 메인스레드에서 사용하기 위해서 runOnUiThread를 사용해야 한다.

override fun onResponse(call: okhttp3.Call, 
          response: okhttp3.Response) {
          runOnUiThread {          
             Toast.makeText(...).show()
          }
      }

 

결론적으로 정리해볼 때, Retrofit을 사용하면 OkHttp로는 얻지 못하는 다음의 장점을 느낄 수 있다.

  1. 어노테이션(Annotation) 사용으로 코드의 가독성이 좋고, 직관적인 설계가 가능하다.
  2. 통신 결과 값을 JSON으로 변환해줄 필요가 없다.
  3. 결과 값을 메인스레드에서 바로 사용할 수 있다.

Retrofit은 훌륭한 가독성과 역질렬화할 필요가 없다는 면만 봐도 아주 쓸만한 라이브러리다. 그렇다고 무조건 Retrofit만 사용하는 것은 아니다. Retrofit 역시 HTTP 통신을 할 때 OkHttp에 의존하고 있고, 두 라이브러리 모두 각각 이점을 가지고 있기 때문에(OkHttp의 경우 OkHttpClient에 네트워크 Intercepter를 통해 API가 통신되는 모든 활동을 모니터링 할 수 있으며 서버 통신 시간 조절이 가능하다는 장점이 있다.), 최고의 성능을 내기 위해서 둘 다 사용하는게 보편적이다.

 

 


참고한 사이트

https://velog.io/@jeongminji4490/Android-OkHttp-Retrofit

 

[Android] OkHttp & Retrofit

안드로이드 스튜디오에서 네트워크 작업을 할 때 주로 사용하는 대표적인 라이브러리로 OkHttp, Retrofit이 있다. 요즘은 Retrofit을 주로 쓰고 부가적인 기능을 위해 OkHttpClient를 Retrofit 객체에 연결해

velog.io

https://itstory1592.tistory.com/130

 

[Android] OkHttp & Retrofit

Android에서 네트워크 작업을 할 때 사용하는 대표적인 라이브러리는 아래와 같다. OkHttp Retrofit 두 라이브러리 모두 Square사에서 개발한 HTTP 통신 라이브러리이다. OkHttp는 HTTP 통신을 간편하게 할

itstory1592.tistory.com

 

'Android > Retrofit' 카테고리의 다른 글

[Android] Retrofit2 - REST API 통신 라이브러리  (0) 2023.09.07