[Android] Serializable, Parcelable
안드로이드에서 액티비티와 같은 안드로이드 컴포넌트에 POJO 같은 데이터를 전달을 해야 할 때가 있다.
액티비티와 같은 안드로이드 컴포넌트들에 데이터를 전달하기 위해서는 반드시 인텐트를 통해 전달하게 된다.
이 때 데이터 객체를 전달할 수 있도록 직렬화 인터페이스로 Serializable과 Parceable을 제공한다.
Serializable
자바 표준 인터페이스 중 하나로 안드로이드 SDK에 포함되어 있지 않다.
전달하고자 하는 데이터 클래스(POJO)에 Serializable 인터페이스를 구현만 하면 액티비티로 데이터를 전달할 준비가 된다.
Java
import java.io.Serializable;
public class CommunityListResponse implements Serializable {
private String USR_NM;
private int COM_ID;
public CommunityListResponse(
String USR_NM,
int COM_ID
) {
this.USR_NM = USR_NM;
this.COM_ID = COM_ID;
}
public String getUSR_NM() {
return USR_NM;
}
public void setUSR_NM(String USR_NM) {
this.USR_NM = USR_NM;
}
public int getCOM_ID() {
return COM_ID;
}
public void setCOM_ID(int COM_ID) {
this.COM_ID = COM_ID;
}
}
Kotlin
data class CommunityListResponseData(
val USR_NM: String,
val COM_ID: Int
) : Serializable
아주 간단하게 Serializable을 Implements로 추가하면 된다.
간단하게 구현하는 만큼 그에 따른 댓가를 치르게 된다. 내부적으로 자바의 리플렉션이 발생하게 된다.
이로 인해 많은 오브젝트 생성과 그에 따른 Garbage Collection이 발생하게 되어 안드로이드 앱의 성능을 낮추고 배터리를 더 잡아먹게 된다.
Parcelable
안드로이드 SDK에 포함된 직렬화 인터페이스
Parcelable은 자바의 리플렉션을 사용하지 않기 위해 특별하게 설계되었다.
Java
import android.os.Parcel;
import android.os.Parcelable;
public class CommunityListResponse implements Parcelable {
private String USR_NM;
private int COM_ID;
public CommunityListResponse(String USR_NM, int COM_ID) {
this.USR_NM = USR_NM;
this.COM_ID = COM_ID;
}
public String getUSR_NM() {
return USR_NM;
}
public void setUSR_NM(String USR_NM) {
this.USR_NM = USR_NM;
}
public int getCOM_ID() {
return COM_ID;
}
public void setCOM_ID(int COM_ID) {
this.COM_ID = COM_ID;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.USR_NM);
dest.writeInt(this.COM_ID);
}
protected CommunityListResponse(Parcel in) {
this.USR_NM = in.readString();
this.COM_ID = in.readInt();
}
public static final Parcelable.Creator<CommunityListResponse> CREATOR = new Parcelable.Creator<CommunityListResponse>() {
@Override
public Person createFromParcel(Parcel source) {
return new CommunityListResponse(source);
}
@Override
public CommunityListResponse[] newArray(int size) {
return new CommunityListResponse[size];
}
};
}
Kotlin
data class CommunityListResponseData(
val USR_NM: String?,
val COM_ID: Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(USR_NM)
parcel.writeInt(COM_ID)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<CommunityListResponseData> {
override fun createFromParcel(parcel: Parcel): CommunityListResponseData {
return CommunityListResponseData(parcel)
}
override fun newArray(size: Int): Array<CommunityListResponseData?> {
return arrayOfNulls(size)
}
}
}
리플렉션을 없애기 위해 보일러플레이트 코드가 생겼지만 퍼포먼스는 향상된다.
옛날 기기 지표이긴 하지만 지금도 동일하게 적용된다. 압도적으로 Parcelable 인터페이스가 데이터를 전달할때 적은 시간을 소요한다.
두 방식 모두 프로세스들 사이에서 통신하는 방식이지만, Serializable은 JVM 상에서 리플렉션 API를 사용한다. 이는 자바 객체 멤버 및 동작을 식별하지만 불필요한 객체(Garbage Objects)도 많이 생성하게 되는데, 이로 인해 Serialzble이 Parcelable보다 느리다.
물론 Serializable 방식에서도 Parcelable처럼 writeObject()와 readObject()를 구현하면 Parcelable보다 빠르다는 의견도 있다고 한다.
Parcelable이 성능이 빠르지만 보일러플레이트 코드를 작성해야 하는 번거로움이 있다.
물론 요즘 안드로이드 스튜디오에서는 자동으로 코드를 생성해주지만 더욱 쉽게 Parcelable을 사용하는 방법을 제공한다.
코틀린에서는 @Parcelize를 사용하면 간단하게 Parcelable을 구현할 수 있다.
@Parcelize
data class CommunityListResponseData(
val USR_NM: String,
val COM_ID: Int
) : Parcelable
Parcelable이 성능이 좋고 단점도 적은만큼 Serializable을 지양하고 Parcelable을 사용하는 것이 바람직하다고 한다.