본문 바로가기
안드로이드 공부 노트

[Android] 안드로이드 Parcelable(@Parcelize) 사용해 액티비티간 데이터(Object) 전달하기 - Kotlin

by 지게요 2022. 10. 28.
728x90
반응형

안드로이드에서의 액티비티 간 Object를 전달하는 방법은 두 가지가 있다.

 

1.  Serializable(직렬화)를 통한 방법

2.  Parcelable interface를 통한 방법

 

이번 공부내용은 두 번째 방법인 Parcelable을 사용해서 액티비티 간 Object를 전달하는 법을 알아보겠다.

# Parcelable란?

- Parcel이라는 뜻을 먼저 해석해보면 소포, 꾸러미등으로 해석이 되고 Parcelable이라 함은 택배로 부칠 수 있는 정도로 해석이 가능하다.

 - Android에서 지원해주는 SDK에 포함되어 있는 인터페이스이다.

 - Serializable 대비 속도면에서 훨씬 빠르다.

# 기존 Parcelable 문제점

 - Parcelable을 구현하는 것은 직접 구현해야 한다 그렇게 때문에 보일러 플레이트 코드(비슷한 코드가 반복되는 것)가 생기게 된다.

 - 위와 같은 이유 때문에 Serializable에 비해 코드 작성 시간이 오래 걸리게 된다.


이러한 문제를 해결해줄 코틀린 parcelize 플러그인이 있어 parcelize를 사용해 액티비티간 객체 전달을 아래 예제를 통해 알아보자!

 

※ 본 예제는 viewbinding을 사용했으므로 viewbinding을 숙지하지 못하면 여기를 통해 먼저 학습하고 오는걸 추천한다.


이번 예제는 간단한 MainActivity에서 SubActivity로 유저 데이터(이름, 나이)를 data class를 통해 넘겨주는 예제이다.

 

# Plugins 추가 (모듈 수준)

plugins {
    ...
    id("kotlin-parcelize")
}

 

# 넘겨줄 객체(data class) 생성

@Parcelize // Parcelable 구현을 위한 어노테이션 추가
data class UserData(
    val name: String,
    val age: Int
) : Parcelable // Parcelable 형으로 리턴

Parcelable 자동으로 구현 해주는 @Parcelize Annotaion을 data class 위에 추가해주고 뒤에 Parcelable을 implement 시킨다.

# xml 생성

<activity_main.xml>

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="첫번째 액티비티"
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/linearLayoutCompat"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/btnSubmit"
        app:layout_constraintTop_toBottomOf="@+id/textView">

        <EditText
            android:id="@+id/inputName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:autofillHints="이름 입력"
            android:hint="이름 입력"
            android:inputType="text" />

        <EditText
            android:id="@+id/inputAge"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:autofillHints="나이 입력"
            android:hint="나이 입력"
            android:inputType="number" />

    </androidx.appcompat.widget.LinearLayoutCompat>

    <Button
        android:id="@+id/btnSubmit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="25dp"
        android:layout_marginHorizontal="15dp"
        android:text="SubActivity 호출"
        app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

<activity_sub.xml>

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SubActivity">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="두번째 액티비티"
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2">

        <TextView
            android:id="@+id/textName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="이름 : "
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="30sp"
            android:textStyle="bold"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textAge"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="나이 : "
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="30sp"
            android:textStyle="bold"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.appcompat.widget.LinearLayoutCompat>

</androidx.constraintlayout.widget.ConstraintLayout>

# 메인액티비티에서 intent를 통해 SubActivity로 객체 전달

<MainActivity.class>

package com.example.parcelizeex

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.parcelizeex.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding
    private lateinit var userData: UserData
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        with(binding){
            btnSubmit.setOnClickListener {
                saveUserData() // userData에 데이터 저장
                val intent = Intent(this@MainActivity,SubActivity::class.java)
                intent.putExtra("USER_DATA",userData) // 기존과 동일하게 putExtra 로 전송
                startActivity(intent)
            }
        }
    }

    private fun saveUserData(){
        userData = UserData(
            name = "${binding.inputName.text}",
            age = "${binding.inputAge.text}".toInt()
        )
    }
}

여기서 봐야할거는 intent로 넘기는 과정에서 일반 String, Int 넘기는 거와 동일하게 putExtra(KEY, VALUS)로 전송한다.

# 서브액티비티에서 intent를 통해 값 받아오기

<SubActivity.class>

package com.example.parcelizeex

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.parcelizeex.databinding.ActivityMainBinding
import com.example.parcelizeex.databinding.ActivitySubBinding

class SubActivity : AppCompatActivity() {
    private lateinit var binding : ActivitySubBinding
    
    // getParcelableExtra 사용해 값 받아오기
    private val userData: UserData? by lazy {
        intent.getParcelableExtra("USER_DATA")
    }
    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivitySubBinding.inflate(layoutInflater)
        setContentView(binding.root)

        with(binding){
            userData?.let { userData ->
                textName.text = "${userData.name}님"
                textAge.text = "${userData.age}살"
            }
        }
    }
}

여기서의 중요 포인트는 기존 String, Int 등 받을 때에는 get자료형 Extra로 받아왔지만 Parcelable 방식으로 넘겨준 객체는 getParcelableExtra(KEY)로 받아온다.

그리고 Null 체크를 꼭 해줘야 한다.

 

※ Array, ArrayList를 받아오고 싶다면 아래와 같은 속성들이 있으니 참고 하길 바란다.

또한 아래 사진을 보면Parcelable은 다양한 유형을 지원한다.

https://developer.android.com/kotlin/parcelize?hl=ko

깃허브

https://github.com/JiSeokYeom/ParcelizeEx.git

 

GitHub - JiSeokYeom/ParcelizeEx

Contribute to JiSeokYeom/ParcelizeEx development by creating an account on GitHub.

github.com

참고
https://developer.android.com/kotlin/parcelize?hl=ko
https://kotlinworld.com/44
반응형