스퀘어에서 만든 HTTP 통신을 간편하게 만들어 주는 라이브러리이다.
동작 방식은 아래와 같다.
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'Retrofit은 JOSN이나 XML 데이터를 모델 객체로 변환해 주는데, 이때 gson 라이브러리 및 컨버터를 사용한다.
모델 클래스는 서버와 주고받는 데이터를 표현하는 클래스이다.
VO (value-object) 클래스라고도 한다.
원래는 JSON 데이터를 코드에서 직접 파싱해서 이용해야 하지만, 데이터를 담을 모델 클래스를 선언하고 클래스 정보만 알려주면 모델 클래스의 객체를 알아서 생성하고 그 객체에 데이터를 담아준다.
{
	"id": 7,
    "email": "abcde@gmail.com",
    "first_name": "hk",
    "last_name": "lee"
}위의 JSON 정보를 담을 모델 클래스는 아래와 같이 작성할 수 있다.
data class UserModel(
	var id: String,
    @SerializedName("first_name")
    var firstName: String,
    var lastName: String
)
// 아래와 같이 클래스를 분리해서 작성할 수 있다.
data class UserListModel(
	var page: String,
    var perPage: String,
    var total: String,
    var totalPages: String,
    var data: List<UserModel>?
    
)@SerializedName 애너테이션을 통해 first_name이라는 키의 데이터가 firstName에 저장된다고 표시한다.
email 프로퍼티는 존재하지 않지만, 문제는 없다.
키가 last_name이면 자동으로 lastName 프로퍼티에 저장된다.
네트워크 통신이 필요한 순간에 호출할 함수를 포함하는 서비스 인터페이스를 작성해야 한다.
interface INetworkService {
	@GET("api/users")
    fun doGetUserList(@Query("page") page: String): Call<UserModel>
    @GET
    fun getAvatarImage(@Url url:String): Call<ResponseBody>
}이 인터페이스를 구현해 실제로 통신하는 클래스는 Retrofit이 자동으로 만들어 준다. 이때 애너테이션을 참조한다.
@GET은 서버와 연동할 때 GET 방식으로 해달라는 의미이다.
@Query는 서버에 전달되는 데이터
@Url은 요청 URL을 의미한다.
val retrofit: Retrofit
	get() = Retrofit.Builder()
    	.baseUrl("https://reqres.in/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()baseUrl을 위 처럼 선언하고 @GET("api/users")처럼 경로를 지정한다면 서버 요청 URL은 "https://reqres.in/api/users" 가 된다.
var networkService: INetworkService = retrofit.create(INetWorkService::class.java)Retrofit의 create()함수에 앞에서 만든 서비스 인터페이스 타입을 전달한다.
그러면 이 인터페이스를 구현한 클래스의 객체를 반환해준다.
// Call 객체 얻기
val userListCall = networkService.doGetUserList("1")인터페이스에 선언한 함수를 호출하면 Call 객체가 반환된다.
실제 통신은 이 Call 객체의 enqueue() 함수를 호출하는 순간 이뤄진다.
userListCall.enqueue(object : Callback<UserListModel> {
	override fun onResponse(call: Call<UserListModel>, response: Response<UserListModel>) {}
    override fun onFailure(call: Call<UserListModel>, t: Throwable) {}통신이 성공하면 onResponse() 함수가, 실패하면 onFailure() 함수가 호출된다.
@GET("users/list?sort=desc")
fun test1(): Call<UserModel>
val call: Call<UserModel> = networkService.test1()@GET("group/{id}/users/{name}")
fun test2(
	@Path("id") userId: String,
    @Path("name") arg2: String,
): Call<UserModel>
val call: Call<UserModel> = networkService.test2("10", "lee")
@GET("group/users")
fun test3(
	@Query("sort") arg1: String,
    @Query("name") arg2: String
): Call<UserModel>
val call: Call<UserModel> = networkService.test3("age", "lee")
// 서버 요청 URL
https://reqres.in/group/users?sort=age&name=lee@GET("group/users")
fun test4(
	@QueryMap options: Map<String, String>,
    @Query("name") name: String
): Call<UserModel>
val call: Call<UserModel> = networkService.test4(
		mapOf<String, String> ("one" to "hello", "two" to "world"),
        "lee"
)
// 서버 요청 URL
https://reqres.in/group/users?one=hello&two=world&name=lee@POST("group/users")
fun test5(
	@Body user: UserModel,
    @Query("name") name: String
): Call<UserModel>
val call: Call<UserModel> = networkService.test5(
	UserModel(id="1", firstName="gildong", lastName="hong"),
    "lee"
)    @Body 애너테이션을 사용하면 서버 요청 URL은 바뀌지 않는다.
@Body로 지정한 모델의 데이터는 데이터 스트림으로 서버에 전송된다.