본문 바로가기

프로그래밍/Android

[HTTP 통신 라이브러리] OkHttp와 Retrofit

🤔 WHAT IS IT?

  • 안드로이드와 서버 간 네트워크 통신을 도와주는 Square사에서 개발한 라이브러리

OkHttp

  • 출시일 : 2013-05-06
  • HttpURLConnection과 Apache HttpClient와 비교하여 HTTP 통신을 편리하게 할 수 있는 라이브러리이다.
  • Interceptor 기능을 사용해 네트워크 제어에 관한 옵션을 세밀하게 설정할 수 있다는 특징이 있다.

Retrofit

  • 출시일 : 2013-05-13
  • OkHttp에 기반을 두고 OkHttp를 추상화 하여 사용할 수 있도록 한 라이브러리이다.
  • Interface와 Annotation을 사용하여 요청을 정의해 직관적이고, Converter Factory를 통해 JSON response를 자동 파싱하여 데이터 처리가 간편하다는 특징이 있다.
    • Annotation: 프로그램에 추가 정보를 제공해주는 메타 데이터(data for data)

 

장점

OkHttp

  • 서버 통신 시간 조절 가능(timeout 지정 가능)
  • Interceptor를 활용한 다양한 기능 구현
    • Application Interceptors
      • 네트워크 요청 및 응답을 가로채 애플리케이션 수준에서 작업을 수행
      • 공통 헤더 추가(매 요청마다 header를 지정할 필요 ❌), 로깅
    • Network Interceptors
      • 네트워크 요청 및 응답을 가로채 네트워크 수준에서 작업을 수행
      • 캐싱, 요청 재시도, 인증 토큰 생성

Retrofit

  • Annotation을 통해 API 엔드포인트를 정의하여 가독성 있는 코드 설계가 가능
  • JSON을 자동으로 파싱해주는 Converter 연동을 지원하여 데이터를 자동으로 파싱하여 유지보수가 쉬움
  • 응답 작업을 자동으로 UI Thread에서 수행할 수 있도록 지원

+ 안드로이드 공식문서에 학습 파트에서 [인터넷에서 데이터 가져오기] 페이지에서 Google에서 만든 Volley 라이브러리가 아닌 Retrofit 라이브러리를 사용하고 있다는 것이 매우 흥미로움

 

인터넷에서 데이터 가져오기  |  Android Developers

커뮤니티에서 개발한 라이브러리를 사용해 Android Kotlin Compose 앱에서 웹 서비스에 연결하여 데이터를 가져오고 표시하는 방법을 알아봅니다. 잠재적인 네트워크 오류를 처리하는 방법도 알아봅

developer.android.com

 

HOW TO USE?

1. 의존성 부여

  • retrofit에는 okhttp 종속성이 추가되어 있음
//okhttp
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0"))
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")

//retrofit
implementation ("com.squareup.retrofit2:retrofit:2.9.0")
implementation ("com.squareup.retrofit2:converter-gson:2.9.0")

 

2. Manifests Permission 부여

<uses-permission android:name="android.permission.INTERNET"/>

 

 

3. 통신

OkHttp

1. Okhttp Client 인스턴스 생성

val client = OkHttpClient()

 

2. Body 생성(POST의 경우)

//1. data를 미리 가공해서 넣어주는 경우
val body = RequestBody.create(MediaType.get("application/json"), "원하는 json 형태의 data")


//2. key-value쌍을 직접 넣어주는 경우
val formBody: RequestBody = FormBody.Builder()
            .add("id", "stella")
            .add("pw", "password").build()

 

3. Request 생성 

  • url, method, body 지정
val request = Request.Builder()
            .url("http://1.23.456.789/test.php")
            .post(formBody)
            .build()

 

4. 서버에 통신 요청 및 응답

  • enqueue() : background thread에서 비동기적으로 수행
    • onResponse()와 onFailure 콜백으로 성공, 실패 처리 쉽게 가능
  • execute() : 현재 thread에서 동기적으로 수행
  • response를 json 형태로 만들어 반환해야함
  •  
client.newCall(request).enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    Log.d(TAG, "onResponse successful: ${response.body().toString()}")
                } else {
                    Log.d(TAG, "onResponse isNotSuccessful: ${response.body().toString()}")
                }

            }

            override fun onFailure(call: Call, e: IOException) {
                Log.d(TAG, "onFailure: ${e.message.toString()}")
            }
        })

 

 

Retrofit

1. 서버와의 통신에서 사용하는 데이터 클래스 생성

data class TestData(
    val result : String,
    val identifier : String,
    val isNewUser : Boolean
)

 

2. Retrofit 인스턴스 생성

  • base url, converterFactory, client 지정(지정 안하면 default okhttp client가 자동으로 지정)
val retrofit = Retrofit.Builder()
            .baseUrl("http://1.23.456.789/") // 실제 서버의 기본 URL로 대체해야 합니다.
            .addConverterFactory(GsonConverterFactory.create())
            .build()

 

3. interface에 request를 정의하고 호출

interface RetrofitService {

    @POST("test.php")
    @FormUrlEncoded
    fun requestLogin(@Field("id") id : String,
                    @Field("pw") pw : String) : Call<TestData>
}

 

val service = retrofit.create(RetrofitService::class.java)

 

4. 서버에 통신 요청 및 응답

  • OkHttp와 동일하게 동기, 비동기 선택 가능
  • 비동기 작업에 대한 callbackdl UI Thread에서 이뤄짐
service.requestLogin("stella", "password").enqueue(object : Callback<TestData> {
            override fun onResponse(
                call: Call<TestData>,
                response: Response<TestData>
            ) {
                if (response.isSuccessful) {
                    Log.d(TAG, "onResponse successful: ${response.body().toString()}")
                } else {
                    Log.d(TAG, "onResponse isNotSuccessful: ${response.body().toString()}")
                }

            }

            override fun onFailure(call: Call<TestData>, t: Throwable) {
                Log.d(TAG, "onFailure: ${t.message.toString()}")
            }
        })

 

OkHttp과 비교하였을 때 Retrofit의 이점

1. 모든 request, response에 대한 Json ↔ Object 변환이 필요하지 않음

2. 요청 시 request 객체를 일일히 만들어줘야 하기 때문에 번거로움을 줄일 수 있음

3. onResponse가 UI thread에서 이뤄지기 때문에 UI 작업 시, runOnUiThread()나 Handler()를 매번 호출하지 않아도 됨

4. base url을 지정해, url 전체를 반복해서 지정하지 않아도 됨

 

 

결론

OkHttp와 Retrofit 중 어느 것이 좋냐고 물어본다면 상황에 따라 다르다고 할 수 있을 것 같다.

둘다 써본 사람으로서 말하자면..처음에 사용하기에는 OkHttp가 수월하긴하다.

Retrofit이 JSON 자동 파싱 및 어노테이션 사용 등 사용자 친화적이긴하나 처음 사용할 때, 조금의 어려움이 있는 것은 사실이다.

본인은 OkHttp로 처음 통신을 시작해서 Retrofit을 사용했을 때 response 타입을 설정해서 받는 것이 혼란스러웠다.

OkHttp는 그런거 없이도 Response가 잘 넘어왔기 때문에!

하지만 쓰다보면 Retrofit이 코드 가독성도 좋고, 직관적이라 협업할때 매우 용이했다👍

 

본인이 처음 Http 통신을 해보는데 시간적 여유가 없어서 빨리 개발에 들어가야 한다하면 OkHttp를 추천하고, REST API 호출이 빈번하고, 협업중이라 코드 가독성이 중요하다 하면 Retrofit을 추천한다(지극히 개인적인 생각)

 

가장 바람직한 방법은 두 라이브러리를 함께 사용해 OkHttp의 다양한 네트워크 제어 기능과 Retrofit의 편리함을 가져가는 방향인 것 같다. (다른 좋은 라이브러리나 방법이 있으면 알려주세요🤙)

 

 

 

 

 

GitHub - square/okhttp: Square’s meticulous HTTP client for the JVM, Android, and GraalVM.

Square’s meticulous HTTP client for the JVM, Android, and GraalVM. - square/okhttp

github.com

 

 

GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM

A type-safe HTTP client for Android and the JVM. Contribute to square/retrofit development by creating an account on GitHub.

github.com