[안드로이드 / Kotlin] Retrofit2

2022. 1. 15. 12:09·Android
반응형

안드로이드 앱 제작에 있어 네트워크 통신은 필수적인 사항이 되었습니다. 

그래서 많은 통신 라이브러리가 존재하는데, 그 중 가장 많이 사용되는 라이브러리인

'Retrofit' 에 대해 알아보도록 하겠습니다.

 

Retrofit 은 동일 Squareup사의 Okhttp 라이브러리의 상위 구현체입니다.

Okhttp와 다르게 (1) AsyncTask를 사용하지 않아 빠른 성능을 가지고 있습니다.

또한 (2) 동기/비동기의 구현이 간단하다는 특징이 있습니다.

간단한 사용방법으로는 아래와 같습니다.

 

 

<사용방법>

 

1. Gradle 추가하기

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

* Gson Converter : JSON 타입의 응답결과를 객체로 변환해주는 컨버터입니다.

 

 

2. 권한 추가하기

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

네트워크 통신에 필요한 인터넷 권한을 Manifest 파일에 추가합니다.

 

 

3. 모델 클래스 선언하기

@Parcelize
data class Data(
    @SerializedName("id")
    val myId: String = "",  
    
    @SerializedName("name")
    val myName: String = "", 
): Parcelable

REST API 로 받아올 데이터를 변환하여 매핑할 클래스를 선언합니다. (클래스명은 상관없습니다.)

(@SerializedName("속성명") 어노테이션을 이용해서 속성명을 일치시켜주면, 원하는데로

변수명을 다르게 선언하여 사용할 수 있습니다. )

 

 

4. 인터페이스 정의하기

interface RetrofitApi {
    // 1
    @GET("API/{id}")
    fun getApi1(@Path("id") id: String): Call<Data>
    
    // 2
    @GET("API")
    fun getApi2(@Query("id") id: String): Call<Data>
    
    // 3
    @GET("API")
    fun getApi3(@QueryMap querys: Map<String, String>): Call<Data>
    
    // 4
    @FormUrlEncoded
    @POST("API")
    fun setPostField(
    	@Field("id") id: String,
        @Field("name") name: String
    ): Call<Data>
    
    // 5
    @FormUrlEncoded
    @POST("API")
    fun setPostField(@FieldMap params: Map<String, String>): Call<Data>
}

- 1, 2, 3번 코드는 Http 메소드 'GET'을 이용한 방법입니다.

1) @GET("API/{id}") / @Path("id") :  먼저 @GET 은 baseUrl 에 연결된 EndPoint 역할을 하며, @Path 는 EndPoint 에서 중괄호 '{}'로 감싸진 변수에 매핑되도록 알려주는 역할을 합니다.  즉, @Path("id") 를 보고 @GET 내부 중괄호 안에 대입합니다. 

2) @Query("id") : URI 에 쿼리를 추가해서 원하는 데이터를 조회할 수 있는 기능입니다.

3) @QueryMap : 위 Query 개념에서 다중쿼리 시 사용합니다.

 

- 4, 5번 코드는 Http 메소드 'POST'을 이용한 방법입니다.

4) @Field("id") : 사용을 위해 먼저 @FormUrlEncoded 어노테이션을 추가해야합니다. 이는 form-urlencoded 방식을 이용하기 때문인데 키-값 방식으로 &(구분자) 사용합니다. (ex) id=10&name="android")

5) @FieldMap : @QueryMap 과 같이 Map 을 이용해 Field 를 한번에 전송할때 사용합니다.

 

* Call<Data> : 응답이 왔을때 콜백으로 불려질 타입입니다.

 

 

5. Retrofit 인스턴스 생성하기

<RequestRetrofit>

class RequestRetrofit(listener: RetrofitResultListener.Listener<Data>,
    errorListener: RetrofitResultListener.ErrorListener): Interceptor {

    private final val TAG = "RequestRetrofit"

    var retrofitApi: RetrofitApi
    var mContext: Context? = null
    var mCall: Call<Data>? = null

    var mListener = listener
    var mErrorListener = errorListener

    init {
        val logging = HttpLoggingInterceptor()  // 로깅를 위한 Interceptor
        logging.setLevel(HttpLoggingInterceptor.Level.BODY)

        val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(logging)	// App interceptor
            .addNetworkInterceptor(this)	// Network interceptor
            .connectTimeout(1, TimeUnit.MINUTES)
            .build()

        val retrofit = Retrofit.Builder()
            .baseUrl(URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()

        retrofitApi = retrofit.create(RetrofitApi::class.java)	// Interface 객체
    }

    // 통신할 메소드 set
    fun setCall(context: Context, call: Call<Data>) {
        mContext = context
        mCall = call
    }

    // Retrofit 비동기통신
    fun enqueue(tag: String) {
        mCall?.enqueue(object: Callback<Data>{
            override fun onResponse(
                call: Call<Data>,
                response: retrofit2.Response<Data>
            ) {
                if(response.isSuccessful) {
                    Log.e(TAG, "onResponse() 성공: 결과=${response.body().toString()}")
                    mListener.onResponse(DATA, tag)
                } else {
                    Log.e(TAG, "onResponse() 실패")
                    mErrorListener.onErrorResponse(null, tag)
                }
            }

            override fun onFailure(call: Call<Data>, t: Throwable) {
                Log.e(TAG, "onFailure(): ${t.message}")
                mErrorListener.onErrorResponse(t.message, tag)
            }
        })
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        
        Log.e(TAG, "**${request.url}")

        return chain.proceed(request)
    }
}

<RetrofitResultListener>

class RetrofitResultListener {

    interface Listener<T> {
        fun onResponse(response: T, tag: String)
    }

    interface ErrorListener {
        fun onErrorResponse(error: String?, tag: String)
    }
}
  • RequestRetrofit : 해당 클래스는 Retrofit 인스턴스 생성 및 통신에 필요한 메소드가 담겨 있는 클래스입니다.
  • RetrofitResultListener : 해당 클래스에는 응답에 대한 인터페이스가 담겨 있습니다. 여러가지 종류의 통신이 이곳 저곳에서 발생하기 때문에 편한 관리를 위해 사용했습니다.(성공: Listener<T>, 실패: ErrorListener)

 - 초기화하는 부분에서 OkHttp 를 사용하는데 그 이유는 OkHttp Client 의 Interceptor 를 통해 API 가 통신되는 활동을 모니터링하며 또 파라미터 및 경과시간에 따른 중단등의 여러 기능을 사용할 수 있기 때문입니다. 

(해당 부분은 다음에 정리해서 다시 올리도록 하겠습니다..)

 

 - enqueue()를 이용해서 비동기 통신을 합니다.(excute()를 이용하면 동기식으로 구현하실 수 있습니다.)

 

 - 통신결과에 대한 콜백으로 onResponse()가 와도 무조건 성공한 것이 아니므로 isSucessful()을 사용해 한번 더 확인해야합니다.

 

 - 각 통신결과에 대한 콜백에 미리 선언했던 RetrofitReulstListener를 이용해 정보를 넘겨줍니다.

 

 

6. 마무리

val request = RequestRetrofit(this, this)	// 리스너 등록
val call = request.retrofitApi.getApi1("abc123")
request.setCall(this, call)
request.enqueue(API_TAG)

마지막으로 위에 선언했던 RequestRetrofit 클래스를 이용해 최종적으로 통신을 하게됩니다.

enqueue()에서 파라미터로 태그를 받는 이유는 많은 API 를 호출할때 구분을 편하게 하기위해서 입니다.

* setCall() : 통신에 사용할 메소드(인터페이스에 정의)  선택

 

 


제가 작성한 부분외에도 더 많은 편리한 기능들을 Retrofit2 에서 지원하고 있습니다. 또한 Retrofit은 OkHttp 의 상위 구현체이기 때문에 OkHttp 도 혼용해서 사용하는 경우가 많습니다. 그래서 다음 기회가 되면 OkHttp Client 는 왜 사용하고 어떻게 사용하는지에 대해 정리해서 올리도록 하겠습니다! 긴 글 읽어주셔서 감사합니다:)

 

* 참고 : https://jaejong.tistory.com/33

 

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

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

jaejong.tistory.com

 

반응형

'Android' 카테고리의 다른 글

[안드로이드 / Kotlin] 진동  (0) 2022.02.13
[안드로이드 / Kotlin] RecyclerView에 대한 고찰  (0) 2022.01.22
[안드로이드 / Kotlin] 생체 인식 인증 사용하기  (0) 2022.01.07
[안드로이드 / Kotlin] 카카오 로그인 SDK v2 사용하기  (0) 2022.01.07
[안드로이드 / Kotlin] Int형을 Byte Array로 나타내기  (0) 2022.01.03
'Android' 카테고리의 다른 글
  • [안드로이드 / Kotlin] 진동
  • [안드로이드 / Kotlin] RecyclerView에 대한 고찰
  • [안드로이드 / Kotlin] 생체 인식 인증 사용하기
  • [안드로이드 / Kotlin] 카카오 로그인 SDK v2 사용하기
서주냥
서주냥
간단한 것도 기록하는 습관을 가지자
  • 서주냥
    DroidLog
    서주냥
  • 전체
    오늘
    어제
    • 전체보기 (58)
      • 알고리즘 (12)
        • 백준 (4)
        • 프로그래머스 (5)
        • 개념 (3)
      • Android (43)
        • Compose (1)
      • Java (2)
      • Kotlin (1)
  • 링크

    • GitHub
  • 인기 글

  • 태그

    블루투스
    BLE
    벨만 포드
    Hilt
    안드로이드
    최단 경로
    reified
    코틀린
    viewmodel
    백준
    Coroutine
    RecyclerView
    프로그래머스
    투 포인터
    이진 탐색
    FusedLocationProviderClient
    클린 아키텍처
    debounce
    ConstraintLayout
    뷰모델
    알고리즘
    코루틴
    moshi
    Coroutine Flow
    SnackBar
    다이나믹 프로그래밍
    자바
    Clean Architecture
    viewpager2
    textunit
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
서주냥
[안드로이드 / Kotlin] Retrofit2

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.