안드로이드 앱 제작에 있어 네트워크 통신은 필수적인 사항이 되었습니다.
그래서 많은 통신 라이브러리가 존재하는데, 그 중 가장 많이 사용되는 라이브러리인
'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 |