직렬화, Serialization #2 -Parcelable

choi jeong heon
슬기로운 개발생활
5 min readDec 4, 2021
parcel

이전 글

정의

Parcel 이란?

우리말로 꾸러미 라는 뜻을 가집니다. 짐을 꾸리듯이 객체의 데이터들의 Container 역할을 하는 클래스입니다.

Parcelable은 직렬화를 위한 또다른 인터페이스입니다. Serializable과 달리 표준 Java가 아닌 Android SDK의 인터페이스입니다.

Parcelable 프로토콜은 객체가 Parcels에서 스스로 쓰고 읽을 수 있도록 매우 효율적인(그러나 저수준) 프로토콜을 제공합니다.

writeParcelable(android.os.Parcelable, int) 및 readParcelable(java.lang.ClassLoader) 또는 writeParcelableArray(T[], int) 및 readParcelableArray(java.lang.ClassLoader) 같은 메서드를 직접 사용하여 쓰거나 읽을 수 있습니다. 이러한 메서드는 클래스 type과 해당 데이터를 모두 Parcel에 기록하므로 나중에 읽을 때 해당 클래스가 적절한 클래스 로더에서 재구성될 수 있습니다. 자세한 내용은 아래에서 살펴보겠습니다.

Parcelable은 Reflection을 사용하지 않도록 설계되었습니다. Serializable 과는 달리 직렬화 처리 방법을 사용자가 명시적으로 작성하기 때문에 자동으로 처리하기 위한 Reflection이 필요 없습니다.

어떻게?

마커 인터페이스인 Serializable과 달리 Parcelable은 구현해야 하는 필수 메서드를 포함하기 때문에 클래스에 보일러 플레이트 코드가 추가 됩니다. 이는 클래스를 이해하기 어렵고, 새로운 기능을 추가 하기 힘들게 만듭니다. 또한 코드의 추가로 클래스가 복잡해 져서 유지 보수가 어려워지는 원인이 됩니다.

  • constructor: Parcel로부터 데이터를 읽어 객체를 생성할 때 사용합니다.
  • writeToParcel: 객체의 데이터를 Parcel에 wrtie할 때 사용됩니다.
  • describeContents: 데이터가 어떤 종류인지 설명합니다. Parcelable 객체가 file descriptor를 포함하고 있다면 CONTENTS_FILE_DESCRIPTOR를 리턴하고 그 외는 0을 리턴하라고 합니다.
  • Parcelable.Creator: 꼭 구현해야 하는 static class입니다. Parcel으로부터 객체를 만들 때 사용합니다.

Parcel 객체를 생성하고 writeValue() 에 직렬화할 객체를 넘겨주면 해당 객체가 Parcel에 쓰여집니다.

writeValue() 내부를 보면, Serializable 처럼, 직렬화할 object의 타입을 체크하는 로직이 있습니다. Parcelable이라면, writeParcelable()을 호출합니다.

writeParcelable() 함수안에서 우리가 override했던 writeToParcel() 을 호출하고 있습니다.

readValue() 는 class loadaer를 넘겨주어 Parcel에 쓰인 데이터를 바탕으로 객체로 역직렬화를 수행합니다. type이 Parcelable이면 readParcelable() 이 호출됩니다.

readParcelable 에서 우리가 작성했던 CREATOR가 사용됩니다.

마무리하며

안드로이드 docs에는 다음과 같은 주의사항이 적혀있습니다.

Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.

Parcel은 범용 직렬화 메커니즘이 아닙니다. 이 클래스(및 임의의 개체를 Parcel에 배치하기 위한 해당 Parcelable API)는 고성능 IPC(프로세스 통신) 전송으로 설계되었습니다. 따라서 Parcel 데이터를 영구 저장소에 배치하는 것은 적절하지 않습니다. Parcel에 있는 데이터의 기본 구현이 변경되면 이전 데이터를 읽을 수 없게 될 수 있습니다.

따라서 직렬화한 객체가 영속적으로 저장되어야 한다면 Parcel은 좋은 옵션이 될 수 없습니다.

--

--