Android/이론 학습

[Android/Kotlin] Intent 에 커스텀 객체 전달하기? 직렬화, 역직렬화 Serializable 과 Parcelable, @Parcelize

노소래 2022. 2. 20. 00:01

[시작하며 (반성)]

한 화면에서 다른 화면으로 이동할 때 데이터를 전달하려고하는 데, Primitive type 이 아닌 내가 만든 data class(디자인 패턴을 관점에서는  POJO 클래스, Model) 을 통째로 전달하고 싶을 수 있다.

액티비티 객체는 안드로이드 시스템에서 관리하는 컴포넌트로 데이터 전달에는 Intent 를 사용하기 때문! 

그리고 최근에 Jetpack navigation 으로 프로젝트를 진행해왔는데, navigation 라이브러리에서도 Serializable 과 Parcelable 을 지원해서 Fragment 간 객체를 전달할 수 있었다.

 

Serializable 과 Parcelable 의 개념을 안드로이드 공부 시작하고 초반에 접하고 따로 더 공부한 적이 없이 자연스레 사용해서 잘 알고있다고 생각했는데,

최근에 면접을 보던 중 둘의 차이와 무엇을 쓸지 질문을 받았을 때 제대로 대답을 못하는 내 모습을 보고 반성하는 차원에서 글로 (코틀린 기준으로) 정리하려고 한다.


[직렬화 역직렬화]

  • 직렬화란 메모리 상 정보를 Byte 단위의 코드를 통해 직렬로 나열하는 것
  • 또한 내 객체 데이터를 네트워크로 전달하거나 데이터베이스에 저장하거나 파일로 만들 수 있는 포맷으로 바꿔주는 기술이다.
  • 역직렬화란 직렬화의 반대로 변환된 데이터를, 즉 외부의 데이터를 다시 객체로 읽고 변환하는 기술이다.

[Serializable]

  • 직렬화할 수 있게 해주는 인터페이스이다.
  • 자바 표준 인터페이스 중 하나이고 안드로이드 SDK 에는 포함되어있지 않다.
  • 장점
    Serializeable 인터페이스만 상속하면 되므로 구현이 편리하다는 장점이 있다. 
  • 단점
    하지만 내부적으로는 자바의 리플렉션이 발생하게 되고 이로 인해 많은 오브젝트 생성과 그에 따른 Garbage Collection 이 발생하게 되어 안드로이드 앱의 성능을 낮추고 베터리를 더 잡아먹게된다는 단점이 있다!
  • 리플렉션이란 자바에서 제공하는 API 로, 생성되어 있는 객체를 통해 해당 객체의 클래스 정보를 분석하는 기법을 뜻한다. 따라서 직렬화, 역직렬화 할 때 리플렉션을 활용하면 그 과정에서 많은 객체를 생성하게 되고, 정보가 많아질 수록 GC 와 CPU 에 부담이 된다는 의미이다. 
  • 사용법은 아래 링크를 참고하자
 

Serialization | Kotlin

 

kotlinlang.org


[Parcelable, Parcelize]

  • Parcelable 은 Parcel 로 쓰여지고 복원될 수 있는 객체를 가진 클래스들을 위한 인터페이스이다.
  • 자바가 아닌 안드로이드 SDK 내에 포함되어있다.
  • Parcel 은 IPC 전송에 높은 성능을 가지게 디자인 되어있다. 그래서 Parcel 데이터를 persistent storage 에 두는 것은 적절하지 않다. (Parcel 의 데이터 구현을 변경이 저장된 데이터를 읽을 수 없게하기 때문인듯?) 
  • Parcelable 인터페이스를 구현한 클래스는 CREATOR 라고 불리는 null 이 아닌 static 필드를 가져야한다.
  • CREATOR 는 Parcelable.Creaator 인터페이스의 구현체이다.
  • 장점
    리플렉션을 사용하지 않게 설계되어있다. 그래서 Serializable 에서의 퍼포먼스 단점을 보완할 수 있다.
  • 단점
    리플렉션을 없애기 위해 보일러플레이트 코드가 생겨 유지보수를 힘들 게 하는 요인이 된다.
     class MyParcelable private constructor(`in`: Parcel) : Parcelable {
         private val mData: Int = `in`.readInt()
    
         override fun describeContents(): Int {
             return 0
         }
    
         override fun writeToParcel(out: Parcel, flags: Int) {
             out.writeInt(mData)
         }
    
         companion object CREATOR: Parcelable.Creator<MyParcelable?> {
             override fun createFromParcel(`in`: Parcel): MyParcelable? {
                 return MyParcelable(`in`)
             }
    
             override fun newArray(size: Int): Array<MyParcelable?> {
                 return arrayOfNulls(size)
             }
         }
     } // https://developer.android.com/reference/android/os/Parcelable​
  • 단점 보완법
    안드로이드 스튜디오(InteliJ IDE)의  Live Template 을 활용하면 쉽게 보일러플레이트 코드를 생성할 수 있다!
    코틀린에서는 @Parcelize 를 사용하면 더욱 쉽게 Parcelable 을 구현할 수 있다.
  • @Parcelize 어노테이션을 사용한 Parcelable 구현 (자세한 내용은 코드 출처링크를 참고하자)
    // build.gradle
    apply plugin: 'com.android.application'
    apply plugin: 'kotlin-android'
    apply plugin: 'kotlin-parcelize'
    
    ...
    
    import kotlinx.parcelize
    
    @Parcelize
    class User(val firstName: String, val lastName: String, val age: Int): Parcelable​
    
    // 출처 https://www.charlezz.com/?p=44613
     

[결론]

  • 안드로이드 프로젝트 진행 중에 객체를 어딘가에 담아서 보내야하는 경우 성능을 위해 Serialize 보다는 Parcelable 을 사용하자
  • 보일러플레이트 코드를 줄이기 위해  @Parcelize 를 활용해보자!

 

[참고 링크]

 

자바 직렬화, 그것이 알고싶다. 훑어보기편 | 우아한형제들 기술블로그

{{item.name}} 자바의 직렬화 기술에 대한 대한 이야기입니다. 간단한 질문과 답변 형태로 자바 직렬화에 대한 간단한 설명과 직접 프로젝트를 진행하면서 겪은 경험에 대해 이야기해보려 합니다.

techblog.woowahan.com

 

Parcelable과 Serializable 비교 | 찰스의 안드로이드

Serializable은 분명히 개발자 입장에서는 편합니다. 인터페이스 구현만 하면되니까요. 하지만 앱 사용자에게는 퍼포먼스저하와 베터리 드래인이라는 큰 단점을 안겨 줍니다. 조금은 귀찮더라도 Se

www.charlezz.com

 

[Android] Serializable vs Parcelable

액티비티 간 데이터 전달을 위한 두 녀석의 차이점

velog.io

 

Parcelable  |  Android Developers

android.net.wifi.hotspot2.omadm

developer.android.com