서버로부터 통신을 받아오려면 어떤게 필요할까?
서버통신이 너무 어려워서 제가 보려고 쓰는 글입니다…
1) 서버 주소를 안드로이드 스튜디오에 입력하기
2) DTO
3) Interface
4) Retrofit Builder
1번 과정부터 생각을 해보자
https://reqres.in/ 이 주소를 이용할 것이다.
우리가 앞서 연습하고자 한 부분의 데이터 구조를 확인해보자.
{
"page": 2,
"per_page": 6,
"total": 12,
"total_pages": 2,
"data": [
{
"id": 7,
"email": "michael.lawson@reqres.in",
"first_name": "Michael",
"last_name": "Lawson",
"avatar": "https://reqres.in/img/faces/7-image.jpg"
},
{
"id": 8,
"email": "lindsay.ferguson@reqres.in",
"first_name": "Lindsay",
"last_name": "Ferguson",
"avatar": "https://reqres.in/img/faces/8-image.jpg"
},
{
"id": 9,
"email": "tobias.funke@reqres.in",
"first_name": "Tobias",
"last_name": "Funke",
"avatar": "https://reqres.in/img/faces/9-image.jpg"
},
{
"id": 10,
"email": "byron.fields@reqres.in",
"first_name": "Byron",
"last_name": "Fields",
"avatar": "https://reqres.in/img/faces/10-image.jpg"
},
{
"id": 11,
"email": "george.edwards@reqres.in",
"first_name": "George",
"last_name": "Edwards",
"avatar": "https://reqres.in/img/faces/11-image.jpg"
},
{
"id": 12,
"email": "rachel.howell@reqres.in",
"first_name": "Rachel",
"last_name": "Howell",
"avatar": "https://reqres.in/img/faces/12-image.jpg"
}
],
"support": {
"url": "https://reqres.in/#support-heading",
"text": "To keep ReqRes free, contributions towards server costs are appreciated!"
}
크게 핵심으로 나눠보면, page, per_page, total, total_pages,data,support이고, 잘 보면 data는 안에 리스트 형식의 내용을, support는 url과 text를 지닌 형태이다.
@GET 이니까 데이터를 받아올테고 따라서 데이터 클래스 이름도 ResponseFriendListDto 로 작성했다.
@Serializable
data class ResponseFriendListDto(
@SerialName("page")
val page: Int,
@SerialName("per_page")
val per_page: Int,
@SerialName("total")
val total: Int,
@SerialName("total_pages")
val total_pages: Int,
@SerialName("data")
val data: List<FriendListData>,
@SerialName("support")
val support: Support,
) {
@Serializable
data class FriendListData(
@SerialName("id")
val id: Int,
@SerialName("email")
val email: String,
@SerialName("first_name")
val first_name: String,
@SerialName("last_name")
val last_name: String,
@SerialName("avatar")
val avatar: String,
)
@Serializable
data class Support(
@SerialName("url")
val url: String,
@SerialName("text")
val text: String,
)
}
잠깐 설명을 덧붙여 보자면, 아래에 FriendListData를 따로 만든 뒤에 해당 클래스를 List 형식으로 바꿔줬고 (val data: List), Support도 따로 만들어서 전체를 넣어준 형태로 만들어줬다.
Q. Serializable은 뭐지? 꼭 필요한 어노테이션인가요?
A. Kotlin의 kotlinx.serialization 라이브러리를 사용하여 객체를 JSON으로 직렬화 또는 역직렬화를 시킬 수 있게 해줍니다. 다시 말해 서버에서 받은 JSON 데이터를 Kotlin 객체로 변환하거나, 객체를 JSON으로 변환해서 서버에 전송할 수 있다는 뜻입니다. (JSON은 서버와 클라이언트간의 소통을 할 수 있게 해주는 만국공통어 같은 느낌!! 위애서 보여준 응답 구조가 JSON으로 쓰인 것 입니다.)
그럼 이번엔 @POST을 연습해봅시다!
{
"authenticationId" : "lyny123",
"password" : "password34!!",
"nickname" : "닉네임적어주세요",
"phone" : "010-0000-0000"
}
회원가입시에 이런 구조를 서버에 보내고 싶다면?
@Serializable
data class RequestSignUpDto(
@SerialName("authenticationId")
val authenticationId: String,
@SerialName("password")
val password: String,
@SerialName("nickname")
val nickname: String,
@SerialName("phone")
val phone: String,
)
이렇게 작성할 수 있겠네요

interface FriendListService {
@GET("api/users")
suspend fun getFriendList(
@Query("page") page: Int,
): ResponseFriendListDto
}
위의 그림을 통해 interface는 이렇게 쓸 수 있겠죠?
@Query는 나중에 다른 게시물로 다루도록 하겠습니다.
해당 인터페이스는 Retrofit을 통해 네트워크 요청을 정의하고, DTO는 그 요청의 응답을 처리하는 데이터 모델 클래스입니다.
Retrofit Builder를 통해 Retrofit 인스턴스를 생성하고
그 Retrofit 인스턴스로 인터페이스 객체(아까 위에서 만든 FriendListService)를 구현합니다!
→ url 숨기는 법은 아래에 나옵니다!
object ApiFactory {
private const val FRIEND_BASE_URL: String = BuildConfig.FRIEND_BASE_URL
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.client(client)
.baseUrl(FRIEND_BASE_URL)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}
inline fun <reified T> create(): T = retrofit.create(T::class.java)
}
object ServicePool {
val friendListService = ApiFactory.create<FriendListService>() //이 부분입니다!!
}
object ApiFactory {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.client(client)
.baseUrl(https://reqres.in/) //이 부분!!
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}
inline fun <reified T> create(): T = retrofit.create(T::class.java)
}
Retrofit을 이용하여 서버통신을 구현하는 ApiFactory에서 직접 URL을 넣고 Git에 올리면 url이 다 보이게 된다.. 그러면 이제 다른 사람들이 내 git에서 URL보고 악용해서 서버 비용이 엄청 많이 나올 수 있게 되겠죠..? 그러면 나만 알게 하려면 어떻게 해야 할까요
1) git에 올라가지 않는 local properties를 이용하면 됩니다.
friend List를 받아오는 url의 이름을 friend.base.url라고 해보겠습니다.
보통 local properties에 작성하는 객체들은 소문자로 작성한다고 하니 유의!!
//local properties
friend.base.url="https://reqres.in/"
# plugin{}과 andriod{} 사이
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
3) build.gradle의 android에서 사용할 객체들을 가져온다
android {
defaultConfig {
...
buildConfigField "String", "Friend_BASE_URL", properties["friend.base.url"]
}
buildFeatures {
...
buildConfig true
}
다시 아까의 안드로이드 ApiFactory로 이동해보자
object ApiFactory {
private const val FRIEND_BASE_URL: String = BuildConfig.FRIEND_BASE_URL //추가해준 부분
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.client(client)
.baseUrl(FRIEND_BASE_URL) //바뀐 부분
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}
inline fun <reified T> create(): T = retrofit.create(T::class.java)
}
주석 부분을 잘 보면
private const val FRIEND_BASE_URL: String = BuildConfig.*FRIEND_BASE_URL*
BuildConfig에 만들어 놓은 *FRIEND_BASE_URL* 를 불러와서 변수에 할당한다는 의미입니다.
그 뒤에 아까 url 자체를 직접적으로 넣었던 곳에 url이 담긴 변수명 *FRIEND_BASE_URL* 을 넣어주면 됩니다!!
1) 먼저 서버로부터 데이터를 주거나, 받아올 데이터의 구조를 작성해준다
2) 사용할 HTTP Method를 정의하는 인터페이스를 작성한다.
→ HTTP Method : @POST, @GET.. 등등
3) 인터페이스 객체를 구현한다.
다음은 Retrofit으로부터 불러온 데이터들을 List Adapter를 이용해서 화면에 표시하는 방법에 대해 게시하겠습니당