티스토리 뷰

728x90

 

Retrofit2

Retrofit2는 HTTP 통신을 도와주는 라이브러리다.

GET, POST, PUT, DELETED 등을 전달하면 서버에서 처리 후 여러 형태의 데이터로 응답을 제공받을 수 있다.

비슷한 역할을 하는 HttpURLConnection 이나 AsyncTask, Volley 라이브러리들은 deprecated 되었고, 사용하기 복잡하기 때문에 현재 Retrofit이 가장 보편적으로 쓰이고 있다.

 

또한 Retrofit2는 OkHttp 기반으로 작동하기 때문에,

OkHttp의 Interpreter를 사용해서 고정적인 헤더를 추가하거나

응답값을 가로채서 원하는 데이터 형태로 가공하는 등의 작업들이 가능하다.

 

https://jsonplaceholder.typicode.com/posts

이러한 Retrofit을 이용해서 위 url에 있는 JSON 데이터를 가져오고, 데이터를 전송하는 코드를 구현해보자.

 

 

 

Retrofit 구현 셋팅

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

builde.gradle에 위 두줄을 추가한다.

첫 번째 줄은 Retrofit을 위한 것이고, 두 번째 줄은 JSON을 자바 클래스로 바로 변환해주는 Gson 라이브러리를 위한 것이다.

 

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

    <application
        ...
        android:usesCleartextTraffic="true">

Manifest.xml에 두줄을 추가한다.

첫 번째 줄은 애플리케이션이 네트워크 연결을 할 수 있도록 허용하는 코드고, 

두 번째 줄은 https가 아닌 http 프로토콜의 url에 접근할 수 있도록 하는 코드다.

(만약 서버가 https라면 생략해도 됨)

 

 

 

API Interface 선언하기

Retrofit을 사용하기 위해, GET/POST 등의 함수가 정의된 인터페이스를 선언한다.

여기서는 간단히 인터페이스명을 API라고 해주었다.

 

interface API {
    @GET("/posts")
    fun getData(@Query("userId") id: String): Call<List<Post>>

    @FormUrlEncoded
    @POST("/posts")
    fun getPostList(@FieldMap param: HashMap<String, Any>): Call<Post>
}

https://jsonplaceholder.typicode.com/posts 에 있는 JSON 데이터 형식은

userId, id, title, body로 구성되어 있다.

 

함수 앞에 있는 @GET("/posts") @POST("/posts")는 사용할 http 함수 종류를 뜻한다.

그리고 어노테이션 안의 인자는 url 주소를 나타낸다.

url 전체는 https://jsonplaceholder.typicode.com/posts 인데, posts만 작성했다.

변하지 않는 서버의 주소는 (https://jsonplaceholder.typicode.com) 추후에 Retrofit 객체를 생성할 때 설정해준다.

 

 

- GET

    @GET("/posts")
    fun getData(@Query("userId") id: String): Call<List<Post>>

 

userId를 인자로 전달하면, 해당하는 인자에 맞는 데이터만 가져올 수 있도록 구현했다.

(예를 들어 인자가 1이면, userId가 1인 JSON 데이터만 가져옴)

이 역할을 @Query("userId")가 한다.

 

그리고 GET을 통해 전달받고 싶은 데이터의 형식을 Call<>안에 써준다.

JSON 데이터를 Post 객체 여러개로 가져오고 싶기 때문에 반환값을 Call<List<Post>>로 설정했다.

 

 

- POST

    @FormUrlEncoded
    @POST("/posts")
    fun getPostList(@FieldMap param: HashMap<String, Any>): Call<Post>

@FieldMap은 key-value 형식으로 데이터를 전달하고 싶을 때 붙이는 어노테이션이다.

 

HashMap으로 데이터를 전달할 때는 @FieldMap을 사용하고,

파라미터로 바로 key-value를 전달할 때는 @Field를 사용한다.

    @FormUrlEncoded
    @POST("/posts")
    fun getPostList(@Field("userId") userId: Int,
                    @Field("id") id: Int,
                    @Field("title") title: String,
                    @Field("body") body: String): Call<Post>

예를 들어 @Field는 위 코드와 같이 사용할 수 있다.

이런 key-value 형식을 form-urlencoded라고 하고,

@FieldMap/@Field를 사용할 때는 무조건 @FormUrlEncoded 어노테이션과 함께 사용한다.

 

 

 

Post 클래스 구현

아까 GET, POST의 응답값으로 Post 객체를 받기로 정의했다.

그러기 위해서는 Post 객체를 직접 구현해야 한다.

 

data class Post(@SerializedName("userId") val userId: Int,
                @SerializedName("id") val id: Int,
                @SerializedName("title") val title: String,
                @SerializedName("body") val body: String)

https://jsonplaceholder.typicode.com/posts 에서 봤듯이,

JSON 형태는 userId, id, title, body로 구성된 형태이기 때문에 그대로 Post의 프로퍼티로 생성해준다.

 

또한 Post를 데이터 클래스로 구현했다.

데이터 클래스는 프로퍼티의 게터/세터를 자동으로 구현해준다.

만약 자바 언어를 사용한다면, 게터와 세터를 직접 구현해야 한다.

 

여기서 @SerializedName이라는 어노테이션은, JSON에 있는 key값과 동일한 값으로 매칭시켜준다는 의미다.

즉, @SerializedName("a") val b: Int라는 프로퍼티가 있다면 JSON key가 a인 데이터를 코틀린 상의 프로퍼티 b에 대입된다.

이 어노테이션이 JSON을 자바 클래스로 변경해주는 Gson의 핵심이라고 할 수 있다.

 

 

 

Retrofit 객체 생성

API 인터페이스는 말그대로 인터페이스이기 때문에 get/post 함수들을 직접 사용할 수는 없다.

Retrofit 객체를 생성해서, API 인터페이스를 구현해야 한다.

 

object RetrofitBuilder {
    var api: API = Retrofit.Builder()
        .baseUrl("http://jsonplaceholder.typicode.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(API::class.java)
}

아까 url의 일부분(/posts)만 지정해주었는데, 변하지 않는 url은 여기서 baseUrl로 설정해준다.

이제 이 RetrofitBuilder에 있는 api 프로퍼티를 통해 get/post 함수들을 직접 호출할 수 있다.

자원 효율성을 위해 RetrofitBuilder을 싱글톤으로 구현했다. (object)

 

여기서 addConverterFactory로 Gson을 전달해줌으로써 Gson을 사용할 수 있다.

 

 

 

get/post 함수 직접 사용하고 응답 받아오기

- GET

        RetrofitBuilder.api.getData("1").enqueue(object : Callback<List<Post>> {
            override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) {
                if (response.isSuccessful) {
                    Log.d(TAG, "getData onResponse()")
                    response.body()?.get(3)?.let { Log.d(TAG, it.title) }
                }
            }

            override fun onFailure(call: Call<List<Post>>, t: Throwable) {
                Log.d(TAG, t.localizedMessage)
            }
        })

enqueue는 Queue에 데이터를 밀어넣는 작업을 뜻한다.

여기서도 enqueue 함수가 사용되는데, 서버의 작업 큐 가장 뒤에 함수 호출을 삽입한다고 생각하면 된다.

서버는 이 작업 큐를 순서대로 처리해 응답을 보낸다.

API 함수들의 반환값은 Call<> 형태였으므로 Call의 enqueue()를 호출하는 것이다. 호출함과 동시에 서버와 통신을 시작한다.

 

응답 값을 처리하기 위해 CallBack 인터페이스를 구현한다.

서버에서 응답을 잘 받아오면 onResponse가 호출되고, 받아오지 못했다면 onFailure가 호출된다.

onResponse에서 한번 더 확인하기 위해 response.isSuccessful을 검사한다.

 

그리고 response.body()가 아까 선언해준 getData 함수의 반환값인 List<Post>가 된다.

여기서는 getData("1")을 해주었기 때문에 userId가 1인 JSON 데이터들이 Post 객체로 변환되어 List에 존재할 것이다.

 

onResponse() 안에 원하는 처리를 해주면 되는데, 테스트를 위해 List의 3번째 데이터의 title을 로그로 출력해보았다.

https://jsonplaceholder.typicode.com/posts 에서 본 것과 동일하게 userId가 1인 3번째 데이터 title이 출력되는 것을 확인할 수 있다.

 

 

- POST

        val input = HashMap<String, Any>()
        input["userId"] = 1
        input["title"] = "title"
        input["body"] = "body"
        
        RetrofitBuilder.api.getPostList(input).enqueue(object : Callback<Post> {
            override fun onResponse(call: Call<Post>, response: Response<Post>) {
                if (response.isSuccessful) {
                    Log.d(TAG, "getPostList onResponse()")
                    Log.d(TAG, "${response.body()?.title}")
                }
            }

            override fun onFailure(call: Call<Post>, t: Throwable) {
                Log.d(TAG, t.localizedMessage)
            }
        })

보낼 데이터를 HashMap에 넣고 인자로 전달한다.

그리고 get과 동일하게 response.body()를 통해 응답값이 제대로 넘어온 것을 확인할 수 있다.

 

 

 

 


 

 

Retrofit에는 이 포스팅에서 사용한 어노테이션 말고도 여러가지가 있고,

DELETE나 PUT 함수를 구현하는 방법도 추후 공부하고 구현해보면서 포스팅 해야겠다.

 

그리고 Retrofit 한글 문서가 있던데, 읽어보면 많은 도움이 될 것 같아서 링크 첨부한다.

https://devflow.github.io/retrofit-kr/

 

Retrofit - 한글 문서

A type-safe HTTP client for Android and Java

devflow.github.io

 

728x90
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함