[Android | Kotlin] Retrofit2

Deer·2021년 3월 23일
5

[Android | Kotlin]

목록 보기
1/1

들어가기 전에


Retrofit이란


Retrofit은 Square에서 제공하는 Third Party Library이다.

Retrofit은 HTTP API 통신을 돕는 라이브러리로 쉽고 직관적인 사용법 덕분에 서버 통신을 할 때, 아주 많이 쓰이고 있다.


초기설정


Gradle 의존성 추가

implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
implementation 'com.squareup.retrofit2:converter-gson:(insert latest version)'

Retrofit2를 사용하기 위해서 Gradle에 의존성을 추가해준다.

보통 서버에 JSON 객체를 통해 요청이나 응답을 주고 받는다. 이 때, 안드로이드에서는 JSON 객체를 바로 사용할 수 없기 때문에 JSON Object → JAVA Object, 혹은 그 반대로의 변환 과정이 필요하다.

이를 도와주기 위해 Gson 라이브러리를 추가해준다.

인터넷 사용 권한 추가

통신을 위해서 인터넷 사용 권한이 필요하다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="example.example">

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

		...
</manifest>

Android Manifest 파일에 추가해준다.


Retrofit 객체 생성


서버와 통신하기 위해서 Retorofit 객체가 필요하다.

Retrofit.Build() 메서드를 통해 Retrofit 객체를 생성할 수 있다.

서버통신은 안드로이드에서 어디서든 필요할 수 있다.

때문에 싱글톤 패턴을 이용해서 Retrofit 객체를 생성해준다.

object RetrofitClass {
    private val retrofit = Retrofit.Builder()
			.baseUrl(BASE_URL)
			.addConverterFactory(GsonConverterFactory.create())
			.build()
}

이렇게 Retrofit 객체를 만들어주면 통신이 필요할 때마다 Retrofit 객체를 끌어서 쓸 수 있다.
BASE_URL에는 서버 ip를 넣어주면 된다.



요청 & 응답 객체 정의


서버 통신을 할 때, 많은 경우 JSON 객체 통해 데이터를 주고 받는다. 응답 형식이 다음과 같은 JSON 객체를 예시로 들어보겠다.

{
	"student" : [
		{
			"student_id": 30410,
			"name" : "홍길동",
			"phone" : "010-12345-1234"
		},
		{
			"student_id": 30411,
			"name" : "고길동",
			"phone" : "010-53455-1256"
		},
		{
			"student_id": 30413,
			"name" : "둘리",
			"phone" : "010-35243-5345"
		},
		{
			"student_id": 30414,
			"name" : "아이유",
			"phone" : "010-13352-5343"
		}
	]
}

위의 JSON 객체는 특정 객체를 배열로 담은 변수를 가진 객체이다.

따라서 Kotlin에서는 다음과 같이 표현할 수 있다.

data class exampleResponse(
	val student: List<Student>
) 

data class Student(
	val studentId: Int,
	val name: String,
	val phone: String
)

JSON에서는 변수를 Snake Case로 표기한다.

반면, Java와 Kotlin에서는 Camel Case로 변수를 표기한다.

Retrofit 통신을 할 때, 서버에 정의된 변수명과 클라이언트에 정의된 변수명이 같으면 스스로 대응시켜 처리해준다.

하지만 위의 student_id의 경우에는 studentId와 자동으로 대응되지 않기 때문에 다음과 같이 수정해야 한다.

data class ExampleResponse(
	val student: List<Student>
) 

data class Student(
	@SerializedName("student_id")
	val studentId: Int,
	val name: String,
	val phone: String
)

SerializedName Annotation를 사용하면 studentId를 student_id로 명시할 수 있다.


API 인터페이스 정의


서버와 통신하기 위해서는 명세된 API에 따라서 Retrofit 객체가 구현할 API Interface를 정의해야 한다.

student API가 다음과 같다고 해보자.

Student Request

다음을 Query parameter로 받는다.
school_id : int (학교 아이디)
grade : int (학년)
classroom : int (학반)

Student Response

{
	"student" : [
		{
			"student_id": 30410,
			"name" : "홍길동",
			"phone" : "010-12345-1234"
		},
		{
			"student_id": 30411,
			"name" : "고길동",
			"phone" : "010-53455-1256"
		},
		{
			"student_id": 30413,
			"name" : "둘리",
			"phone" : "010-35243-5345"
		},
		{
			"student_id": 30414,
			"name" : "아이유",
			"phone" : "010-13352-5343"
		}
	]
}

Student Api는 학교 아이디와 학년, 학반을 쿼리로 받아 그에 해당하는 학생들을 배열에 담아 응답하는 GET Api이다. 앞서 정의한 ExampleResponse를 이용해 다음과 같이 표현할 수 있다.

interface ExampleInterface {
	@GET("student")
	fun getStudent(@Query("school_id") schoolId: Int,
			@Query("grade") grade: Int,
			@Qeury("classroom") classroom: Int): Call<ExampleResponse>
}

getStudent 메서드는 schoolId와 grade, classroom을 파라미터로 받고 Call 객체를 리턴하는 함수이다.

통신 처리를 할 때는 비동기 처리를 해야 하기 때문에 Retrofit2에서 제공하는 Call 객체를 사용해 Callback을 구현할 수 있다.

이제 생성한 Retrofit 객체가 이 Api Interface를 구현하면 Retrofit 객체를 통해 Api를 사용할 수 있다.

object RetrofitClass {
    private val retrofit = Retrofit.Builder()
			.baseUrl(BASE_URL)
			.addConverterFactory(GsonConverterFactory.create())
			.build()
		
		private val _api = retrofit.create(ExampleInterface::class.java)
		val api
			get() = api
}



통신 처리


이제 Retrofit 객체와 API를 모두 정의하였으니, 서버와 통신할 준비를 모두 끝냈다.

val schoolId = 10102
val grade = 2
val classroom = 4
val callGetStudent = RetrofitClass.api.getStudent(schoolId, grade, classroom)

callGetStudent.enqueue(object : Callback<ExampleResponse> {
	override fun onResponse(call: Call<ExampleResponse>, response: Response<ExampleResponse>) {
		if(response.isSuccessful()) { // <--> response.code == 200
			// 성공 처리
			
			//ex)
			Toast.makeText(this, "${response.body().student.size}", Toast.LENGTH_SHORT).show()
		} else { // code == 400
			// 실패 처리
		}
	}
	
	override fun onFailure() { // code == 500
		// 실패 처리
	}
}

Callback 객체를 callGetStudent에 넣어서 응답이 날라오면 적절히 처리할 수 있게 해준다.

Callback 객체를 익명 인터페이스로 만든 다음 onResponse와 onFailure 메서드를 구현해준다.
서버와 통신이 성공하면 onReponse를 호출하고, 실패하면 onFairure를 호출한다.

응답 코드가 200이 아닌 400이여도 onResponse를 호출하기 때문에 if(response.isSuccessful())을 이용해서 성공 처리를 해준다.



마무리


Retrofit은 사용법 자체가 간단하고 유용해서 굉장히 많이 쓰이는 라이브러리이다.

Retrofit은 Gson 뿐만 아니라 Jackson 등 여러 Converter를 지원하며, RxJava와 같이 쓰면 더욱 쉽고 깔끔하게 코드를 짤 수 있다.

profile
대구소프트웨어마이스터고등학교 5기 안드로이드 개발자

0개의 댓글