
안녕하세요 👋
오늘은 Serializable 과 Parcelable 의 차이점에 대해서 정리해보려고 합니다!
앱에서 사용하는 객체는 메모리(JVM Heap)에 존재하는데,
이 객체를 다른 외부 자바 시스템에 전달 하기 위해 바이트 배열로 변환 하고 다시 복원하는 일련의 과정을 직렬화라고 말합니다.
즉, 메모리 내 객체 → 바이트 배열 → 다시 객체로 복원하는 과정
Android 아래 상황들에서 흔히 사용합니다.
- 다른 Activity로 전달
- 네트워크 전송
- 파일/SharedPreferences/DB에 저장
- IPC(프로세스 간 통신)
Serializable 이란 Java 표준 직렬화 인터페이스로 메서드가 없는 마커 인터페이스입니다. 구현은 매우 간단 (그냥 : Serializable만 붙이면 끝) 하지만 Reflection 기반이기 때문에 Android 환경에서 성능 저하가 발생 할 수 있습니다.
data class User(
val name: String,
val age: Int
) : Serializable
구체적인 클래스 타입을 알지 못해도 객체를 통해 클래스 정보를 분석하여 런타임에 메서드/타입/변수들에 접근할 수 있도록 해주는 자바 API입니다.
Reflection 은 런타임에 메타데이터 탐색 + 접근자 검사 + 박싱 등 오버헤드가 많아서 기본적으로 CPU 비용이 발생하고 GC가 빈번하게 발생하여 성능저하를 발생 시킬 수 있습니다.
data class User(
val name: String,
val age: Int,
@Transient val debugTag: String,
) : Serializable
간단하게 @Transient 를 붙여주면 해당 필드는 직렬화에서 제외 됩니다.
Parcelable 은 안드로이드 컴포넌트 내에서 프로세스 통신(IPC)을 위해 특별히 설계된 안드로이드 특정 인터페이스입니다.
IPC에서 사용되는 Parcel 포맷을 기반으로 설계되어 Reflection 이없고,개발자가 직접 필드 읽기/쓰기를 구현하는 구조 입니다. 그래서 Serializable 보다 성능이 빠릅니다.
🤔 IPC(Inter‑process communication)란?
IPC는 프로세스 간 통신의 약자로 서로 다른 프로세스가 서로 통신하고 데이터를 공유할 수 있도록 하는 메커니즘 입니다. 별도의 애플리케이션이나 시스템 서비스 간의 협업을 가능하게 하며, 안드로이드에서는
Binder,Intents,ContentProviders,Messenger와 같은 컴포넌트를 통해 IPC가 이루어집니다.
data class User(val name: String, val age: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}
override fun describeContents() = 0
companion object CREATOR : Parcelable.Creator<User> {
override fun createFromParcel(parcel: Parcel) = User(parcel)
override fun newArray(size: Int): Array<User?> = arrayOfNulls(size)
}
}
Parcelable 위와 같이 직접 읽기/쓰기를 직접 구현해야 하는점이 단점이 있지만, Kotlin에서 지원하는 @Parcelize 를 통해 손쉽게 구현이 가능합니다.
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
@Parcelize
data class User(
val name: String,
val age: Int,
) : Parcelable
만일 지원하지 않는 타입의 경우
Parceler를 통해 직접 구현이 가능합니다.
https://developer.android.com/kotlin/parcelize
@Parcelize
data class User(
val name: String,
val age: Int,
@IgnoredOnParcel val debugTag: String
) : Parcelable
@Parcelize 또한 간단하게 @IgnoredOnParcel 을 통해 간단하게 구현이 가능합니다.
Serializable 과 Parcelable 은 모두 객체를 직렬화하는 도구입니다. 각각의 장단점이 존재 하는데, Serializable 은 사용이 간단하지만 Reflection 기반이라는 구조적 한계가 있어 성능 면에서 불리하고, Parcelable 은 안드로이드 IPC 환경을 위해 설계된 만큼 훨씬 빠르고 효율적으로 동작합니다.
다만, 최근에는 @Parcelize 를 통해 구현 난이도도 크게 낮아졌기 때문에, 컴포넌트 간 데이터 전달이나 상태 저장과 같이 Android 내부에서 사용될 객체라면 Parcelable 을 기본으로 선택하는 것이 가장 실용적인 접근이라는 생각이 듭니다.
그렇지만, 해당 데이터가 어디서 어떻게 사용 되는지, 현재 어떤 상황에 놓여 있는지에 따라 어떤것을 쓸지는 개발자가 선택하는것이 맞다고 생각합니다!
이상으로 오늘 포스팅을 마치며 이 글이 여러분에게 도움이 되었으면 좋겠습니다. 😇
오늘도 즐코하세요 🙇♂️
Android Developers 공식 문서 (Parcelable)
Android Developers 공식 문서 (Parcelize)
Android Manifest Interview <저자: 엄재웅(skydoves)>