반응형
안드로이드 개발을 하다 보면 액티비티(Activity) 간, 혹은 서비스(Service) 간 데이터를 전송해야 하는 경우가 많습니다. 이때 자주 사용되는 방법이 Serializable과 Parcelable이며, 실제 데이터를 담아 전달하는 그릇 역할로 Parcel이 사용됩니다. 이번 포스팅에서는 각각이 무엇이며 왜 쓰이는지, 어떤 상황에서 더 유용한지, 간단 예제까지 살펴보겠습니다.
1. Serializable
1.1 특징
- Java 표준 인터페이스: java.io.Serializable 인터페이스를 구현하기만 하면 됩니다.
- Reflection 기반: 런타임에 리플렉션을 통해 필드를 직렬화하기 때문에 단순 구현이 가능하지만, 그만큼 속도가 느리고 오버헤드가 큼.
- 사용 용도: 안드로이드가 아닌 순수 Java 환경에서도 사용 가능. 안드로이드에서 간단한 객체 전달에 사용할 수 있으나, 성능이 크게 중요하지 않을 때 추천됩니다.
1.2 장단점
- 장점:
- 손쉽게 구현 가능
- Java 표준이므로 범용적
- 단점:
- 상대적으로 느린 직렬화
- 오버헤드가 큼(가비지 객체 생성 많음)
1.3 간단 예제 (Kotlin)
// 직렬화할 클래스
import java.io.Serializable
data class MySerializableData(
val name: String,
val age: Int
) : Serializable
// 사용 예시 (Activity 간 전달)
// 첫 번째 Activity
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("myData", MySerializableData("Alice", 20))
}
startActivity(intent)
// 두 번째 Activity에서 받는 법
val myData = intent.getSerializableExtra("myData") as? MySerializableData
myData?.let {
Log.d("SecondActivity", "이름: ${it.name}, 나이: ${it.age}")
}
2. Parcelable
2.1 특징
- 안드로이드 전용 인터페이스: android.os.Parcelable 인터페이스를 구현해야 합니다.
- 성능 최적화: 내부적으로 리플렉션을 사용하지 않고, 직접 읽고 쓰는 방식을 제공해 빠른 직렬화가 가능합니다.
- 사용 용도: 안드로이드 환경에서 액티비티 간 데이터 전달이나 IPC(Inter-Process Communication) 상황에서 자주 사용. 성능이 중요한 경우 Parcelable을 권장합니다.
2.2 장단점
- 장점:
- 빠른 직렬화 및 역직렬화
- 가비지 객체 생성이 적어 메모리 효율적
- 단점:
- 구현이 다소 번거로움(생성자, writeToParcel, CREATOR 등)
2.3 간단 예제 (Kotlin)
// 직렬화할 클래스
import android.os.Parcel
import android.os.Parcelable
data class MyParcelableData(
val name: String,
val age: Int
) : Parcelable {
// Parcel에서 읽어들이는 생성자
constructor(parcel: Parcel) : this(
parcel.readString().toString(),
parcel.readInt()
)
// 객체 직렬화
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}
// 보통 0 리턴
override fun describeContents(): Int = 0
companion object CREATOR : Parcelable.Creator<MyParcelableData> {
override fun createFromParcel(parcel: Parcel): MyParcelableData {
return MyParcelableData(parcel)
}
override fun newArray(size: Int): Array<MyParcelableData?> {
return arrayOfNulls(size)
}
}
}
// 사용 예시 (Activity 간 전달)
// 첫 번째 Activity
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("myData", MyParcelableData("Bob", 25))
}
startActivity(intent)
// 두 번째 Activity에서 받는 법
val myData = intent.getParcelableExtra<MyParcelableData>("myData")
myData?.let {
Log.d("SecondActivity", "이름: ${it.name}, 나이: ${it.age}")
}
3. Parcel
3.1 Parcel이란?
- 안드로이드에서 IPC를 위한 데이터를 담는 컨테이너 클래스입니다.
- 안드로이드 내부에서 객체를 다른 컴포넌트로 전달할 때, 객체를 flatten(직렬화) 하고 다시 unflatten(역직렬화) 하는 과정을 수행합니다.
- Parcel 자체는 일반적인 직렬화 용도로 쓰면 안 되며, 파일로 저장하거나 네트워크 전송 용도로 적합하지 않습니다. (안드로이드 버전에 따라 Parcel 구조가 달라질 수 있음)
3.2 Parcel과 Parcelable의 관계
- Parcelable을 구현한 객체는 Parcel을 통해 직렬화/역직렬화됩니다.
- Parcel은 기본 자료형(문자열, 정수 등)부터 배열, Parcelable 객체 등을 효율적으로 쓰고 읽을 수 있도록 메서드를 제공합니다.
4. Serializable vs. Parcelable 비교 표
구분SerializableParcelable
타입 | Java 표준 인터페이스 | 안드로이드 전용 인터페이스 |
---|---|---|
성능 | 느림(리플렉션 사용) | 빠름(리플렉션 미사용, 직접 처리) |
가비지 생성 | 많음 | 적음 |
사용 편의 | 구현 간단 | 구현 복잡 |
주 사용 용도 | 안드로이드 외도 가능 | 안드로이드 내에서 주로 사용 |
5. 어떤 것을 선택해야 할까?
- 성능이 중요한 경우: Parcelable을 권장합니다. 예를 들어 큰 데이터를 자주 주고받거나, IPC가 빈번하게 발생하는 경우, Parcelable로 작성된 객체가 훨씬 빠르게 직렬화/역직렬화됩니다.
- 간단하고 범용적인 코드가 필요한 경우: 안드로이드 밖의 Java 환경과도 호환하려면 Serializable을 사용할 수 있습니다. 구현이 간단하므로 성능 요구 사항이 낮은 경우에 괜찮습니다.
- 규모가 큰 앱: 대규모 앱일수록 Parcelable를 사용해 불필요한 오버헤드를 줄이는 것이 좋습니다.
- 간단한 테스트나 프로토타입: 개발 단계에서 빠르게 구조를 잡고 테스트하려면 Serializable도 나쁘지 않습니다. 추후에 필요에 따라 Parcelable로 변환할 수 있습니다.
6. 결론
- Serializable:
- 장점: 간단, Java 표준, 안드로이드 외에서도 사용 가능
- 단점: 느리고 오버헤드가 많음
- 추천 상황: 데이터가 적고, 성능에 크게 구애받지 않을 때, 또는 안드로이드 외 코드와 공유가 필요할 때
- Parcelable:
- 장점: 빠른 직렬화, 가비지 최소화
- 단점: 구현 복잡
- 추천 상황: 안드로이드 환경에서 자주 데이터를 전달하거나 성능이 중요할 때
- Parcel:
- 안드로이드 IPC를 위한 핵심 클래스
- 직접 사용하는 경우는 상대적으로 적지만, Parcelable을 구현할 때 내부적으로 Parcel을 이용해 데이터를 쓰고 읽습니다.
- 일반 저장 용도(예: 파일)로 사용해서는 안 됩니다.
안드로이드 개발을 진행하다 보면 많은 경우에 Parcelable이 권장되지만, 상황에 따라 Serializable을 택해야 하는 때도 있을 것입니다. 각 방식의 장단점을 잘 파악하고, 어플리케이션의 성능 요구사항과 개발 편의성을 모두 고려해 선택하는 것이 좋겠습니다.
참고
반응형
'안드로이드' 카테고리의 다른 글
안드로이드로이드에서 Constants를 효율적으로 사용하려 어떻게 해야할까? (1) | 2025.02.15 |
---|---|
안드로이드 jetcaster 예제 분석 - Flow와 Combine을 이용한 흐름 제어 (0) | 2025.01.19 |
MVI란? 안드로이드에서 MVI는 무엇이고 어떻게 적용할까? (0) | 2025.01.19 |
Dagger의 @Binds vs @Provides, @Qualifier vs @Named, @Lazy<T> vs @Provider<T> (0) | 2022.08.29 |
컴포즈 부수효과 (0) | 2022.07.30 |