Developing Myself Everyday
article thumbnail

사진: UnsplashArisa Chattasa

 

 

안드로이드 개발을 하면서 서버에서 데이터를 받아와야 하는 경우가 상당히 많이 발생합니다. 이때 서버에서 보내주는 데이터의 형식은 대부분 JSON 데이터 형식으로 보내집니다.

 

이러한 JSON 데이터로 변환하기 위해서는 직렬화(Serialization) 과정을 거쳐야 하고, JSON 데이터를 받아서 원하는 데이터 구조로 변환하려면 역직렬화(Deserialization) 과정을 가져야 합니다.

 

이번 게시글에서는 안드로이드에서 이러한 JSON 데이터를 다룰 수 있게 해주는 다양한 라이브러리를 살펴보고자 합니다.


 

 

 

 

Json


먼저 Json이 어떻게 되어있는지 한번 살펴보겠습니다.

 

 

Json 응답은 대괄호로 표시된 배열입니다. Json 객체는 중괄호로 묶여 있고, 각 Json 객체에는 이름 - 값 쌍의 집합이 포함됩니다.

 

 

 

 

Gson


Gson은 Java 객체를 JSON 표현으로 변환하거나, JSON 문자열을 Java 객체로 변환하는데 사용할 수 있는 Java 라이브러리입니다. 이름에서 알 수 있듯이 Google에서 제공합니다.

 

그렇기에 코틀린에 친화적이지는 않습니다. 2008년에 출시되었기에, 더 이상 업데이트 되지도 않습니다.

 

만약 Person이라는 데이터 클래스에 Json 데이터를 역직렬화 하려면 아래와 같이 할 수 있습니다.

data class Person(val name: String, val age: Int, val email: String)

val person: Person = Gson().fromJson(`json 데이터`, Person::class.java)

 

 

데이터를 가져올 때 가장 많이 사용되는 방법인 Retrofit2에서 Gson을 사용하는 법은 더 간단합니다. 이전엔 Gson 클래스의 객체를 생성하고, 직접 Json으로 역직렬화를 해 줬지만 Retrofit2에서는 자체적으로 Gson 컨버터를 만들어주는 Factory 클래스를 제공합니다.

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build()
val api = retrofit.create(RetrofitInterface::class.java)

 

 

이전에 말했듯이 Gson의 서비스는 더 이상 업데이트 되지 않습니다. 당연히 Gson을 사용하는 것은 문제 없습니다. 다만 더 나은 방법을 찾고 개선시키는 것이 개발자의 덕목이라고 생각합니다.

 

 

 

 

Moshi


Moshi는 안드로이드에서 자바 및 코틀린을 위한 현대적인 JSON 라이브러리입니다. JSON을 자바나 코틀린 클래스로 파싱하는 작업을 쉽게 할 수 있게 해줍니다.

 

또한 Moshi에는 코틀린 용 코드 생성 어댑터가 있어 성능을 향상시킬 수 있습니다. 애노테이션을 통해 직렬화/역직렬화를 휠씬 빠르게 만들 수 있고, Gson이 사용하는 오래된 리플렉션 방법을 우회할 수 있습니다.

 

Moshi의 가장 큰 특징은 바로 Okio를 기반으로 개발되었고 애노테이션을 사용해서 간단하게 적용할 수 있다는 점입니다.

Okio
Okio는 `java.io` 및 `java.nio`를 보완하여 데이터에 쉽게 액세스하고 저장하며 처리하기 위한 라이브러리입니다. 이것은 Android에 포함된 강력한 HTTP 클라이언트인 OkHttp의 구성 요소로 시작되었습니다.

 

 

Moshi로 직렬화하기 위해서는 먼저 Moshi 객체를 생성하고 Json 직렬화를 위한 어댑터를 추가합니다.

 

Retrofit2에서 Moshi를 사용하는 경우에도 Moshi와 연동되는 컨버터가 존재하기에 해당 컨버터에 Moshi 객체를 넣어 컨버터 팩토리를 만듭니다.

val moshi = Moshi.Builder()
   .add(KotlinJsonAdapterFactory())
   .build()
   
val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .build()
val api = retrofit.create(RetrofitInterface::class.java)

 

 

Moshi는 이러한 어댑터를 통해 Json 데이터를 파싱하기 전에 미리 해당 데이터 클래스의 필드 타입 정보를 파악하여, 파싱할 때 매핑하여 사용하고 있습니다. 

 

이 부분이 바로 Gson과의 가장 큰 차이를 만드는 부분입니다. Gson은 런타임 시점에 클래스의 필드를 동적으로 검색하기 때문에 성능 문제가 발생하게 됩니다. 반면, Moshi는 이러한 정보들을 컴파일 타임에 미리 알아둬서 나중에 동적으로 검색할 때 발생하는 성능 문제를 해결했습니다.

 

 

 

 

Kotlin Serialization


Kotlin Serialization은 코틀린을 위한 Json 라이브러리로, Json 직렬화를 할 수 있는 가장 편하고 좋은 방법이라고 생각합니다.

 

자바로 되어있지 않기에 다양한 멀티플랫폼을 지원할 수 있으며, 다양한 문제를 해결했습니다.

 

이를 사용하는 방법은 `Serializable` 어노테이션을 추가하면 됩니다.

@Serializable
data class Person(
    val name: String,
    val age: Int,
    val email: String
)

 

 

기존의 다른 직렬화 라이브러리들은 직렬화할 때, 데이터 클래스의 초기값을 허용하지 않았고, 코틀린의 특성인 null safety를 지원하지 않았기 때문에 여러 상황에서 효율적으로 적용하기가 어려웠습니다.

 

Kotlin Serialization은 더 다루기 쉽고 다양한 방식으로 직렬화할 수 있게 합니다. 실제로 제가 적용하고 있는 프로젝트의 일부분을 가져와서 사용하는 예시를 보여드리겠습니다.

 

아래와 같은 데이터 클래스에 Retrofit2 인터페이스를 사용해서 직렬화한 데이터를 넣어주는 코드를 작성합니다.

@Serializable
data class AreaCodeResponse(
    val response: Response
)

interface TourAreaCodeApi {
    @GET("areaCode1")
    suspend fun getAreaCode(
        @QueryMap queryParams: Map<String, String>,
        @Query("areaCode") areaCode: String? = null
    ): AreaCodeResponse
}

 

 

그 다음으로 Json을 처리하기 위한 Kotlinx Serialization의 Json 객체를 생성하고 제공합니다. 여기서 JsonBuilder에 접근해서 여러 기본 설정을 할 수 있습니다. 

@Provides
@Singleton
fun provideJson(): Json = Json {
    ignoreUnknownKeys = true
}

 

 

다음으로 Json 객체를 받아서 Json을 변환하는데 필요한 ConverterFactory를 생성합니다.

@Provides
@Singleton
fun provideConverterFactory(json: Json): Converter.Factory =
    json.asConverterFactory("application/json".toMediaType())

 

 

이제 이렇게 만든 ConverterFactory로 Retrofit2 객체를 생성하고 이전에 만들었던 인터페이스로 서버와의 통신을 진행합니다.

@Provides
@Singleton
fun provideRetrofit(
    okHttpClient: OkHttpClient,
    converterFactory: Converter.Factory,
): Retrofit =
    Retrofit.Builder()
        .baseUrl(TOUR_API_BASE_URI)
        .addConverterFactory(converterFactory)
        .client(okHttpClient).build()

@Provides
@Singleton
fun provideTourAreaCodeApi(retrofit: Retrofit): TourAreaCodeApi =
    retrofit.create(TourAreaCodeApi::class.java)

 

 

이러한 단순한 통신 외에도 서버로부터 다양한 응답이 내려올 때에도 그게 맞춰서 대응하게 설계할 수도 있고, 다양한 코틀린의 라이브러리들을 연계해서 사용할 수 있습니다. 

 

 

Serialization 이면 리플렉션을 사용하는가?


안드로이드에서 직렬화를 수행한다면, ParcelableSerializable을 비교해 본적이 있을 것이라 생각합니다.

 

이 둘의 가장 큰 차이를 간단하게 설명하자면, Serializable은 리플렉션을 사용하고 Parcelable은 리플렉션을 사용하지 않는다는 점인것 같습니다.

 

Serialization은 이와 다릅니다. 단순하게 생각했을 때에는 Serializable이 리플렉션을 사용했기에 이름이 유사한 Serialization도 리플렉션을 사용할 것 같습니다.

 

다만, Kotlinx Serialization 라이브러리는 @Serializable 어노테이션이 있는 클래스만 직렬화 하기 때문에 컴파일 타임에 이미 직렬화할 클래스를 전부 알고있습니다. 그렇기 때문에 리플렉션을 사용할 필요가 없어졌습니다.

 

 

 

 

마무리


이렇게 해서 안드로이드에서 사용할 수 있는 다양한 Json 직렬화 라이브러리를 살펴보았습니다. 각자의 장단점이 존재하지만, 마지막에 설명한 Kotlin Serialization 라이브러리는 다른 라이브러리에 비해 장점이 상당히 많습니다. 그렇기에 확실하게 Kotlin Serialization 에 대해서 이해하고 사용법을 배워 놓는다면, 당분간은 직렬화에 대해 걱정할 필요가 없어지지 않을까 생각합니다.

 

 

Reference

 

인터넷에서 데이터 가져오기  |  Android 개발자  |  Android Developers

커뮤니티에서 개발한 라이브러리를 사용해 Android Kotlin 앱에서 웹 서비스에 연결하여 데이터를 검색하고 표시하는 방법을 알아봅니다. 잠재적인 네트워크 오류를 처리하는 방법도 알아봅니다.

developer.android.com

 

Goodbye Gson, Hello Moshi

Time to migrate your Android projects from Gson to Moshi

proandroiddev.com

 

GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back

A Java serialization/deserialization library to convert Java Objects into JSON and back - GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back

github.com

 

GitHub - square/moshi: A modern JSON library for Kotlin and Java.

A modern JSON library for Kotlin and Java. Contribute to square/moshi development by creating an account on GitHub.

github.com

 

GitHub - square/okio: A modern I/O library for Android, Java, and Kotlin Multiplatform.

A modern I/O library for Android, Java, and Kotlin Multiplatform. - GitHub - square/okio: A modern I/O library for Android, Java, and Kotlin Multiplatform.

github.com

 

GitHub - Kotlin/kotlinx.serialization: Kotlin multiplatform / multi-format serialization

Kotlin multiplatform / multi-format serialization - GitHub - Kotlin/kotlinx.serialization: Kotlin multiplatform / multi-format serialization

github.com

 

profile

Developing Myself Everyday

@배준형

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!