Parcelize란 무엇일까?

주효은·2024년 10월 28일
0

Parcelize라는 Annotation을 본 적이 있으신가요?

안드로이드 개발을 하다 보면 @Parcelize라는 annotation을 자주 볼 수 있습니다.

  • Parcelize는 과연 어떤 역할을 할까요?
  • 직렬화 해준다는 것은 잘 알고 있는데, 직렬화란 무엇일까요??
  • 진짜 Parcelize를 쓰면 코드가 간결해지나요?

이해를 돕기 위해 사용자 정보(아이디와 비밀번호)를 담은 User 객체를 다른 화면으로 넘기는 상황을 가정해 보겠습니다.


@Parcelize 없이 데이터 전달하기

안드로이드에서는 Activity나 Fragment 간 데이터를 전달할 때, 객체를 직렬화할 필요가 있습니다. Parcelable 인터페이스를 구현하지 않고 단순히 객체를 넘기려고 하면 에러가 발생합니다. 객체의 데이터를 다른 Activity로 넘기기 위해서는, Parcelable 또는 Serializable로 직렬화가 필요합니다.

그치만! 이번에는 @Paracelize 없이 User 객체가 다음과 같은 구조로 정의되어 있다고 가정해 봅시다.

  • 아니 잠깐..!! 직렬화가 뭐예요?
    직렬화는 객체를 Byte 형태로 변환해, 화면 전환이나 프로세스 간에 데이터를 전달할 수 있도록 해줍니다. 객체를 직렬화해야 하는 이유는 데이터를 안전하고 효율적으로 전달하기 위해서인데요. 안드로이드의 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) 데이터 클래스에 필드가 추가될 때마다 putExtragetExtra 코드를 추가해야 합니다. 이렇게 되면 필드가 많아질수록 코드가 복잡해지고 관리가 어려워집니다. 특히, 앱이 성장하고 유지보수가 길어질수록 수정할 부분이 많아질 수 있습니다.

2) 객체를 Parcelable로 처리하면 User 객체를 그대로 전달하고 사용할 수 있지만, 필드별로 분해해 넘기는 경우 객체의 캡슐화 원칙이 깨질 수 있습니다. 필드별로 넘기면 해당 객체를 재구성하는 코드가 분산되어 나타납니다. 객체를 넘기는 의도를 분명히 하고 구조적으로 유지하기 어려워, 코드가 중복되고 목적이 분산되어 보이기 쉽습니다.

알겠어요.. Parcelable 쓸게요

가장 먼저 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의 차이점은 무엇일까요?!?! 안드로이드 개발에서는 어떤 방식이 더 선호될까요?!!? 그건 다음에 적어보도록 하겠습니다 ㅎㅎ

0개의 댓글