안드로이드 개발을 하다 보면 @Parcelize라는 annotation을 자주 볼 수 있습니다.
Parcelize는 과연 어떤 역할을 할까요?이해를 돕기 위해 사용자 정보(아이디와 비밀번호)를 담은
User객체를 다른 화면으로 넘기는 상황을 가정해 보겠습니다.
@Parcelize 없이 데이터 전달하기안드로이드에서는 Activity나 Fragment 간 데이터를 전달할 때, 객체를 직렬화할 필요가 있습니다. Parcelable 인터페이스를 구현하지 않고 단순히 객체를 넘기려고 하면 에러가 발생합니다. 객체의 데이터를 다른 Activity로 넘기기 위해서는, Parcelable 또는 Serializable로 직렬화가 필요합니다.
그치만! 이번에는 @Paracelize 없이 User 객체가 다음과 같은 구조로 정의되어 있다고 가정해 봅시다.
Intent, Bundle, SavedStateHandle 같은 데이터 전달 메커니즘은 메모리 상의 객체 자체를 전달할 수 없습니다. 대신, 이들은 직렬화된 데이터만을 받아들이기 때문에, 객체를 직렬화하여 전송해야 합니다.data class User(
val id: String,
val password: String
)
이렇게 User를 담은 data class가 있다고 가정해볼게요!
// 현재 액티비티에서 NextActivity로 데이터를 넘긴다고 가정
val user = User(id = "user123", password = "password123")
val intent = Intent(this, NextActivity::class.java).apply {
putExtra("user_id", user.id)
putExtra("user_password", user.password)
}
startActivity(intent)
과제 할 때 많이 봤던 구조죠? 이렇게 하나씩 데이터를 넘겨주셨던 기억이 있으실 겁니다
// NextActivity에서 데이터 받기
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_next)
val userId = intent.getStringExtra("user_id")
val userPassword = intent.getStringExtra("user_password")
// 받은 데이터 사용
if (userId != null && userPassword != null) {
val user = User(id = userId, password = userPassword)
// user 객체 사용
}
}
지금은 전달하고 받아오는 데이터가 총 2개 뿐이라서 별로 복잡해 보이지 않지만, 만약 여러개의 데이터를 전달하고 받아야하는 상황이라면..?
여러가지 문제점들이 있는데요
1) 데이터 클래스에 필드가 추가될 때마다 putExtra 및 getExtra 코드를 추가해야 합니다. 이렇게 되면 필드가 많아질수록 코드가 복잡해지고 관리가 어려워집니다. 특히, 앱이 성장하고 유지보수가 길어질수록 수정할 부분이 많아질 수 있습니다.
2) 객체를 Parcelable로 처리하면 User 객체를 그대로 전달하고 사용할 수 있지만, 필드별로 분해해 넘기는 경우 객체의 캡슐화 원칙이 깨질 수 있습니다. 필드별로 넘기면 해당 객체를 재구성하는 코드가 분산되어 나타납니다. 객체를 넘기는 의도를 분명히 하고 구조적으로 유지하기 어려워, 코드가 중복되고 목적이 분산되어 보이기 쉽습니다.
가장 먼저 build.gradle에 kotlin-parcelize 플러그인을 추가해줍니다
plugins {
id 'kotlin-parcelize'
}
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class User(
val id: String,
val password: String
) : Parcelable
@Parcelize 어노테이션 없이는 수동으로 모든 것을 구현해줘야 하는 불편함이 있습니다.
엄청 귀찮습니다..ㅋ 찾아보시면
// 현재 액티비티에서 NextActivity로 데이터를 넘긴다고 가정
val user = User(id = "user123", password = "password123")
val intent = Intent(this, NextActivity::class.java).apply {
putExtra("user_data", user)
}
startActivity(intent)
// NextActivity에서 데이터 받기
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_next)
val user = intent.getParcelableExtra<User>("user_data")
// 받은 user 객체 사용
user?.let {
// 예: it.id, it.password 사용
}
}
이렇게 하면! 너무나도 간단하게 객체로 데이터를 주고 받을 수 있겠죠 ㅎㅎ
그럼에도 모든 데이터를 직렬화 해줄 필요는 없다고 생각합니다. (이렇게 써놓고?ㅋ..) 단순한 데이터인 String, Int, Boolean 등은 Parcelable없이도 바로 전달 할 수 있습니다. 또한 데이터가 한 화면 내에서만 사용된다면 굳이 이렇게까지 해줄 필요는 없겠죠. 그치만 뭐 우리는 간단한 앱만 만들건 아니니.. 앞으로 자주 볼 Parcelable에 대해서 알아두시면 나쁠건 없을 것 같네요!
그러면.. 직렬화에는 두가지 방식이 있는데요 Parcelable vs Serializable의 차이점은 무엇일까요?!?! 안드로이드 개발에서는 어떤 방식이 더 선호될까요?!!? 그건 다음에 적어보도록 하겠습니다 ㅎㅎ