[Android Library] Retrofit2 #1 - 레트로핏 기본 개괄
REST API 통신을 사용하고자 한다면, 레트로핏을 쓰는게 가장 깔끔하고 편하다.
주로 비동기 통신 구현을 위해 그동안 사용해 왔는데 한 번쯤 정리의 필요성을 느껴 기본 개괄과 HTTP 요청 방식 정리로 두 번의 포스트에 걸쳐 정리하고자 한다.
HTTP GET 메소드의 구현을 예시로 하겠다. 언어는 Kotlin 으로 하겠다.
선행 사항
다음 기술들을 선행하면 좋다.
- REST API (POST, GET, PUT, DELETE) & CRUD (Create, Read, Update, Delete)
- 비동기 통신
기본 정보 및 장점
- Squareup사 에서 만든 라이브러리로 OkHttp의 위에서 구동되는 구현체이다.
- AsyncTask 가 아닌 백그라운드 스레드를 실행하여 콜백으로 결과를 제어할 수 있다. (성능 향상)
- 콜백으로 제어하는 결과는 Main Thread 에서 UI를 업데이트 할 수 있게한다
- Annotation 을 통해 가독성이 뛰어나다.
- 기존 HTTP 통신 구현에 필요했던 반복적인 작업을 라이브러리가 자동화하여 처리한다.
Retrofit의 주요 구성
보통 아래의 순서대로 구현을 진행한다.
- Data Transfer Object (DTO) : JSON 타입 변환에 사용할 객체
- 인터페이스 : Annotation 기반, 서버에 CRUD 동작을 요청할 HTTP 메소드 정의 인터페이스
- Retrofit 객체 : 인터페이스에서 정의한 메소드를 호출할 수 있는 인스턴스
환경 설정
1. App 수준 Gradle의 Dependencies
implementation 'com.squareup.retrofit2:retrofit:2.4.0' // REST API
implementation 'com.squareup.retrofit2:converter-gson:2.4.0' // REST API json parser
여기서 converter-gson 은 Gson Converter를 사용하기 위함으로, 이 컨버터는 JSON 응답 결과를 DTO로 매핑해준다.
( 같은말 : JSON 응답을 Java나 Kotlin 객체로 바꿔준다)
2. AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<application
중략..
android:usesCleartextTraffic="true">
<activity
..
당연히 인터넷 권한을 허용해야하고, application 에서 android:usesCleartextTraffic="true"도 추가한다.
1. DTO 정의
예를들어 앱이 서버에 본인 인증 문자를 발송하는 GET 요청 을 한다고 가정하자.
요청시에는 다음과 같은 URI가 필요하고 (아래 IP는 내 서버 아이피를 살짝바꾼거라 요청해도 소용없다!)
http://54.180.13.2:80/api/sms/verify?phoneNumber=01022115987&hashCode=aaaaaaaaaaa
응답은 다음과 같은 JSON 데이터가 온다고 가정하자.
{
"isSuccess": true,
"code": 202,
"message": "본인인증 문자 발송 성공"
}
응답 JSON의 구조를 파악했다면 다음과 같이 데이터 클래스를 정의한다. (클래스명 무관)
반드시 타입을 일치시켜야 한다!
data class Result(
val code: Int,
val isSuccess: Boolean,
val message: String
)
2. 인터페이스 정의
인터페이스는 우리가 HTTP 요청이 필요해 보이는 메소드를 정의해 놓는다. 여기서 Annotation을 활용한다.
이 메소드는 서버에 인증문자를 보내라고 요청하는 메소드이다.
앞서 아래와 같은 URI 로 요청을 한다고 했다. 여기서 GET 요청의 Path와 쿼리를 유심히 본다.
http://54.180.13.2:80/api/sms/verify?phoneNumber=01022115987&hashCode=aaaaaaaaaaa
interface Network {
@GET("/api/sms/verify")
fun requestAuthMsg(
@Query("phoneNumber") phoneNumber:String,
@Query("hashCode") hashCode:String) : Call<Result>
}
URI를 기반으로 인증 메시지를 요청하는 메소드를 정의하였다. 응답 객체 아까 정의한 DTO를 사용한다. Call<DTO>
이 반환 타입은 응답에 대한 콜백 처리에 이용된다.
@GET("/api/sms/verify") : 이 메소드는 GET 요청임을 알리고, 서버내의 경로(path)를 지정한다.
이 메소드의 각 파라미터는 URI에 명시된 쿼리를 지정한다. 반드시 서버에서 요구하는 이름과 같게 적는다.
@Query("phoneNumber")
@Query("hashCode")
3. Retrofit 인스턴스
이제 인터페이스에서 정의한 메소드를 사용할 수 있는 Retrofit 인스턴스를 생성한다. 이 인스턴스를 필요한 곳에서 활용하여 메소드를 호출하면 된다.
(필요한곳 : 액티비티 & 서비스 등의 컴포넌트)
액티비티나 서비스에서 인스턴스를 생성해도 된다. 하지만 어차피 똑같은 호출 구조이고 가독성을 높히기 위해 Object 파일로 싱글톤 느낌으로 만들어두는게 깔끔하다.
object RetrofitClient {
private const val BASE_URL:String = "http://54.180.13.2:80"
private val retrofit:Retrofit.Builder by lazy{
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
}
val apiService: Network by lazy{
retrofit.build().create(Network::class.java)
}
}
BASE_URL 에 서버 주소를 명시한다. 여기서 / 를 조심해야한다.
http://54.180.13.2:80
이렇게 적었으면 HTTP 메소드 Annotation 에서 /api/sms/verify 로 경로를 적는게 맞다.
http://54.180.13.2:80/
이렇게 적었으면 HTTP 메소드 Annotation 에서 api/sms/verify 로 경로를 적는게 맞다.
슬래시가 한번 들어가야하기 때문이다.
많은 사람들이 여기서 처음에 실수해서 맞왜틀을 외치는 사례가 구글에 낭자하다.
Retrofit.Builer 를 통해 메서드 체인으로 인스턴스의 환경을 설정한다. 베이스 URL 지정과 컨버터를 지정해준다.
응답 형식이 JSON 이기에 GsonConverterFactory.create() 를 반드시 추가해준다.
apiService 객체(이름 무관)가 실제로 컴포넌트에서 사용하게 될 객체이다. 여기서 인스턴스를 생성하는데, 필요한 시점에 생성하도록 지연 초기화하게 했다.
4. 메소드 호출
액티비티가 실행되는 시점에 요청 메소드를 호출한다고 하자.
http://54.180.13.2:80/api/sms/verify?phoneNumber=01022115987&hashCode=aaaaaaaaaaa
인자로 필요한 값을 건네준다.
이제 콜백만 정의하면 된다. 응답이 오면 Result (DTO) 객체에 들어오고 이를 활용한다.
성공적으로 응답이 오면 onResponse, 서버가 꺼져있다던가 여러가지 이유로 실패한다면 onFailure 가 실행된다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
.. 중략
apiService.requestAuthMsg("01022115987","aaaaaaaaaaa").enqueue(object : Callback<Result>{
override fun onResponse(call: Call<Result>, response: Response<Result>) {
expireTime = 180
mTimerHandler?.postDelayed(mTimerRunnable,1000)
}
override fun onFailure(call: Call<Result>, t: Throwable) {
t.printStackTrace()
}
}
다음 포스트에서는 각 HTTP 요청 방법(GET, POST 등) 및 멀티파트 파일업로드 방법을 작성하겠다.
'Mobile : Android > Library' 카테고리의 다른 글
[Android Library] Retrofit2 #2 - HTTP Method (0) | 2021.09.17 |
---|---|
[Android Library] Tensorflow Lite - Sound Classification (0) | 2021.08.25 |
[Android Library] PyTorch Mobile - Speech Recognition (0) | 2021.07.09 |
댓글