SW 공부노트

[안드로이드/Kotlin] Retrofit 라이브러리 본문

안드로이드/안드로이드 공부

[안드로이드/Kotlin] Retrofit 라이브러리

요빈 2023. 4. 12. 12:37

Retrofit

Retrofit은 REST API 통신 라이브러리로 가장 많이 사용되는 대표적인 라이브러리이다.

동일 OkHttp 라이브러리의 상위 구현체로 OkHttp를 네트워크 계층으로 활용하고 그 위에 구축된다.

Async Task 없이 Background Thread를 실행한다. -> Callback을 통해 Main Thread에서 UI 업데이트

Retrofit 장점

  • 빠른 속도 : 자체적 비동기 실행과 스레드 관리가 가능해 속도가 빠르다.
  • 간단한 구현 : 반복된 작업을 라이브러리로 넘겨 처리한다.
    • HttpUrlConnection의 Connection / Input & OutputStream / URL Encoding 생성 및 할당의 반복작업
    • OkHttp의 쿼리 스트링, Request / Response의 반복 설정 작업
  • 가독성 : Annotation 사용으로 코드의 가독성이 뛰어나고, 직관적인 설계가 가능하다
  • 동기 / 비동기 쉬운 구현
    • 동기: 요청-응답이 하나의 트랜잭션(작업)에서 발생, 요청 후 응답까지 대기
    • 비동기: 요청-응답은 별개의 트랜잭션으로 분리, 요청 후 다른 작업을 하다 응답이 도착하면 Callback으로 처리

3가지 구성요소

  • DTO(Data Transfer Object): 모델(Model), Retrofit 호출 결과로 받는 JSON 타입을 원하는 타입으로 변환하는 데 사용
  • Interface: 사용할 HTTP CRUD 동작(메서드)들을 정의해놓은 인터페이스
    • CRUD(Create / Read / Update / Delete) -> Http 메서드(POST / GET / PUT / DELETE)
  • Retrofit.Bulder 클래스: Interface를 사용할 인스턴스, baseUrl, Converter 설정

사용 방법

1. build.Gradle

 

Retrofit / Converter(변환기) 라이브러리 추가

// Retrofit 라이브러리
implementation 'com.squareup.retrofit2:retrofit:2.6.4' 

// Gson 변환기 라이브러리
implementation 'com.squareup.retrofit2:converter-gson:2.6.4'    

// Scalars 변환기 라이브러리
implementation 'com.squareup.retrofit2:converter-scalars:2.6.4'

//Moshi 사용 시
// Moshi
implementation 'com.squareup.moshi:moshi-kotlin:1.9.3'
// Retrofit with Moshi Converter
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
  • Gson Converter: JSON 타입의 응답 결과를 객체로 매핑(변환)해주는 Converter
  • Scalars Converter: 응답 결과를 String 자체로 받아서 보여주는 Converter
    • 사용자가 직접 변환하는 경우 사용
  • Moshi / Jackson 등 여러 Converter 존재

2. 인터넷 권한 설정

 

AndroidManifest 파일에서 인터넷 권한 추가 -> 네트워크 통신에 필요

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

3. DTO 모델 클래스 생성

 

REST API로 받아올 데이터를 변환하여 매핑할 DTO 클래스 선언

JSON 응답을 예로 들면, JSON 응답의 키들이 담긴 데이터 클래스를 선언하면 된다.

data class User(
    val userId: Int,

    val id: String,

    @SerializedName("body")
    val bodyValue: String
)

 

  • @SerializedName("속성명"): JSON의 키 값과 클래스 변수명이 일치하지 않을 경우 사용 -> 일치하면 명시하지 않아도 됨
  • 응답 결과가 XML일 경우 @Element(name="속성명")을 사용
  • Moshi를 사용하면 @Json(name="속성명") 사용

4. Interface 정의

 

사용할 API 선언

interface RetrofitService {

    //GET 예제
    @GET("posts/1")
    fun getUser(): Call<User>

    @GET("posts/{page}")
    fun getUserPage(@Path("page") page: String): Call<User>

    @GET("posts/1")
    fun getStudent(@Query("school_id") schoolId: Int,
                   @Query("grade") grade: Int,
                   @Query("classroom") classroom: Int): Call<ExampleResponse>

    //POST 예제
    @FormUrlEncoded
    @POST("posts")
    fun getContactsObject(@Field("idx") idx: String): Call<JsonObject>
}

5. Retrofit 인스턴스 생성

 

Retrofit 인스턴스를 생성한 후 object 내에서 ServiceAPI 지연 초기화

 

  • Converter(Gson, Moshi) 인스턴스 생성
  • Retrofit.Build를 통해 Retrofit 인스턴스 생성
  • baseUrl, Converter 속성 설정
    • Converter 등록 시 Converter 인스턴스 사용
    • baseUrl은 반드시 "/"으로 끝나야 한다.
  • Converter는 여러개 등록이 가능하다. 등록 순서대로 변환 가능 여부를 판단해 변환이 불가능하면 다음 컨버터를 확인한다.
    • GsonConvert를 마지막에 넣는 걸 추천한다(Gson은 변환이 불가능해도 가능하다고 함)
  • object 객체 이용해 Retrofit 인스턴스인터페이스 객체 구현 -> 싱글톤 사용
    • RetrofitApi.retrofitService 통해 메서드 사용 가능
private const val BASE_URL = "http://serveraddress"

// Gson
private val gson = GsonBuilder()
    .setLenient().create()

// Moshi
private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()
    
private val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

object RetrofitApi{
    val retrofitService: ServiceApi by lazy{
        retrofit.create(ServiceApi::class.java)
    }
}

6. Retrofit 호출

 

  • 비동기 통신 작업 실행
    • 비동기 enqueue 작업으로 실행, 통신종료 후 이벤트 처리 위해 Callback 등록
      • 콜백 재정의 메서드가 2개(onResponse, onFailure)이므로 object로 받아 람다식으로 작성
    • 성공 여부에 따라 메인 쓰레드에서 처리할 작업 등록
      • onResponse: 무조건 성공은 아님 -> reponse.isSuccesful() 확인 필요(실패코드에도 호출되기 때문)
      • onFailure: 실패
val service = RetrofitApi.retrofitService
service.setBoard().enqueue(object : Callback<List<ResponseClass>> {
        override fun onResponse(
            call: Call<List<ResponseClass>>,
            response: Response<List<ResponseClass>>
        ) {
            if (response.isSuccessful) {
                // 성공
                }
            } else {
                Log.e("setBoard - isNotSuccessful", response.toString())
            }
        }

        override fun onFailure(call: Call<List<ResponseClass>>, t: Throwable) {
            Log.e("setBoard - onFailure", t.message!!)
            t.printStackTrace()
        }
    })

* 비동기 통신이므로 백그라운드에서 동작하여 UI 작업을 할 경우, 통신 완료 후 onResponse 내 작업보다 UI가 먼저 표시되어 UI에 값이 뒤늦게 표시되는 등의 문제가 있을 수 있다.

 

* Android에서는 Main Thread(UI Thread)에서 네트워크 통신을 할 수 없다.

UI Thread에서 네트워크 통신을 할 경우 통신 속도 때문에 메인 스레드가 마비될 수 있기 때문이다.

 

* response에 따른 동기적인 처리가 필요할 경우 -> Thread(Thread.sleep()) 사용

 


Reference 및 참고

https://minchanyoun.tistory.com/44

 

[kotlin][Android] retrofit2 (레트로핏) 사용방법

Retrofit2 - REST API 통신 라이브러리? API 통신을 위해 구현된 OkHTTP의 HTTP 통신을 간편하게 만들어주는 라이브러리를 뜻함 Async Task가 없이 Background 쓰레드를 실행 -> CallBack을 통하여 Main Thread에서 UI를

minchanyoun.tistory.com

https://jaejong.tistory.com/33

 

[안드로이드] Retrofit2 '레트로핏' - 기본 사용법

Retrofit2 - REST API 통신 라이브러리 'Retrofit' - REST통신 라이브러리 기본 개념 & 사용법 통신 라이브러리 중 가장 많이 사용되는 대표적인 라이브러리 ( Squareup 사의 라이브러리) Retrofit 이란? REST API

jaejong.tistory.com

https://velog.io/@hs0204/Retrofit2-enqueue%EB%B9%84%EB%8F%99%EA%B8%B0%EB%A5%BC-%EB%8F%99%EA%B8%B0%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0

 

Retrofit2 enqueue(비동기)를 동기로 바꾸기

데이터가 들어오면 그 순서대로 처리가 되는 줄 알았는데 중구난방이었다......생각 않고 코드를 짰다가 낭패를 봤다…우선 예제로 돌릴 나의 삽질 코드부터 보자.1\. 순서대로 Retrofit을 생성해

velog.io