본문 바로가기
Development/Android

[Android] Android ArrayList 객체를 Intent로 전달하는 3가지 방법

by 은스타 2020. 4. 8.
반응형
Android ArrayList 객체를 Intent로 전달하는 3가지 방법

Android ArrayList 객체를 Intent로 전달하는 3가지 방법

안드로이드 개발에서 Activity 간 데이터를 전달할 때, ArrayList와 같은 컬렉션 객체를 전달해야 하는 경우가 자주 발생합니다. 예를 들어, 사용자가 선택한 여러 항목의 목록이나 검색 결과 리스트를 다른 화면으로 넘겨야 할 때가 있습니다. 이 글에서는 ArrayList 객체를 Intent로 안전하게 전달하는 3가지 방법과 각각의 장단점, 그리고 실전에서 사용할 수 있는 코드 예제까지 상세히 알아보겠습니다.
목차
1. Serializable을 이용한 ArrayList 전달
2. Parcelable을 이용한 ArrayList 전달
3. 기본 타입 ArrayList 전달 방법
4. 3가지 방법 비교와 선택 기준
5. 주의사항과 문제 해결

#1. Serializable을 이용한 ArrayList 전달
가장 간단하고 직관적인 방법은 Serializable 인터페이스를 구현하는 것입니다. 이 방법은 코드가 간결하고 구현이 쉽지만, 성능 면에서는 다소 느릴 수 있습니다.
1) 데이터 클래스에 Serializable 구현
우선 인자로 전달하기 위해서는 ArrayList에 담기는 데이터 클래스가 직렬화(Serializable interface를 구현)가 되어 있어야 합니다.
(1) Java로 Serializable 구현
// Serializable을 구현한 데이터 클래스
public class Subway implements Serializable {
    private int lineNumber;
    private String stationName;

    public Subway(int lineNumber, String stationName) {
        this.lineNumber = lineNumber;
        this.stationName = stationName;
    }

    // Getter, Setter 메서드
    public int getLineNumber() { return lineNumber; }
    public String getStationName() { return stationName; }
}
(2) Kotlin으로 Serializable 구현
// Kotlin에서는 더 간단하게 구현 가능
data class Subway(
    val lineNumber: Int,
    val stationName: String
) : Serializable
. . . . .
2) Intent에 ArrayList 담아서 전달하기
(1) Java 코드 예제
// ArrayList 생성 및 데이터 추가
ArrayList<Subway> subwayList = new ArrayList<>();
subwayList.add(new Subway(201, "시청"));
subwayList.add(new Subway(202, "을지로입구"));
subwayList.add(new Subway(203, "을지로3가"));

// Intent에 담아서 전달
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("subway", subwayList);
startActivity(intent);
(2) Kotlin 코드 예제
// ArrayList 생성 및 데이터 추가
val subwayList = arrayListOf(
    Subway(201, "시청"),
    Subway(202, "을지로입구"),
    Subway(203, "을지로3가")
)

// Intent에 담아서 전달
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("subway", subwayList)
startActivity(intent)
. . . . .
3) 전달받은 데이터 꺼내서 사용하기
(1) Java에서 데이터 받기
// Intent에서 ArrayList 꺼내기
ArrayList<Subway> subwayList =
    (ArrayList<Subway>) getIntent().getSerializableExtra("subway");

// null 체크 및 데이터 사용
if (subwayList != null) {
    for (Subway subway : subwayList) {
        Log.d("TAG", "Line: " + subway.getLineNumber() +
            ", Station: " + subway.getStationName());
    }
}
(2) Kotlin에서 데이터 받기
// Intent에서 ArrayList 꺼내기 (안전한 캐스팅)
val subwayList = intent.getSerializableExtra("subway") as? ArrayList<Subway>

// null 체크 및 데이터 사용
subwayList?.forEach { subway ->
    Log.d("TAG", "Line: ${subway.lineNumber}, Station: ${subway.stationName}")
}

#2. Parcelable을 이용한 ArrayList 전달
Parcelable은 안드로이드에서 권장하는 방법으로, Serializable보다 훨씬 빠른 성능을 제공합니다. 다만 구현 코드가 다소 복잡합니다.
1) Parcelable 구현하기
(1) Java로 Parcelable 구현
public class Subway implements Parcelable {
    private int lineNumber;
    private String stationName;

    public Subway(int lineNumber, String stationName) {
        this.lineNumber = lineNumber;
        this.stationName = stationName;
    }

    // Parcel에서 데이터 읽기
    protected Subway(Parcel in) {
        lineNumber = in.readInt();
        stationName = in.readString();
    }

    // Parcel에 데이터 쓰기
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(lineNumber);
        dest.writeString(stationName);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    // CREATOR 필드 (필수)
    public static final Creator<Subway> CREATOR = new Creator<Subway>() {
        @Override
        public Subway createFromParcel(Parcel in) {
            return new Subway(in);
        }

        @Override
        public Subway[] newArray(int size) {
            return new Subway[size];
        }
    };
}
(2) Kotlin으로 Parcelable 구현 (@Parcelize 사용)
// Kotlin에서는 @Parcelize 어노테이션으로 간단하게 구현
// build.gradle에 kotlin-parcelize 플러그인 추가 필요
import kotlinx.parcelize.Parcelize

@Parcelize
data class Subway(
    val lineNumber: Int,
    val stationName: String
) : Parcelable
. . . . .
2) Parcelable ArrayList 전달 및 수신
(1) ArrayList 전달하기
// ArrayList 생성
val subwayList = arrayListOf(
    Subway(201, "시청"),
    Subway(202, "을지로입구")
)

// Intent에 Parcelable ArrayList 담기
val intent = Intent(this, SecondActivity::class.java)
intent.putParcelableArrayListExtra("subway", subwayList)
startActivity(intent)
(2) ArrayList 받기
// Intent에서 Parcelable ArrayList 꺼내기
val subwayList = intent.getParcelableArrayListExtra<Subway>("subway")

// 데이터 사용
subwayList?.forEach { subway ->
    Log.d("TAG", "Line: ${subway.lineNumber}, Station: ${subway.stationName}")
}

#3. 기본 타입 ArrayList 전달 방법
커스텀 객체가 아닌 String, Integer 등의 기본 타입 ArrayList를 전달할 때는 더욱 간단한 방법을 사용할 수 있습니다.
1) String ArrayList 전달
// String ArrayList 전달
val stationNames = arrayListOf("시청", "을지로입구", "을지로3가")

val intent = Intent(this, SecondActivity::class.java)
intent.putStringArrayListExtra("stations", stationNames)
startActivity(intent)

// 받는 쪽
val stationNames = intent.getStringArrayListExtra("stations")
. . . . .
2) Integer ArrayList 전달
// Integer ArrayList 전달
val lineNumbers = arrayListOf(201, 202, 203, 204)

val intent = Intent(this, SecondActivity::class.java)
intent.putIntegerArrayListExtra("line_numbers", lineNumbers)
startActivity(intent)

// 받는 쪽
val lineNumbers = intent.getIntegerArrayListExtra("line_numbers")

#4. 3가지 방법 비교와 선택 기준
각 방법의 장단점을 비교하여 상황에 맞는 최적의 방법을 선택할 수 있습니다.
1) 세 가지 방법 비교표
방법 장점 단점 권장 사용
Serializable 구현이 매우 간단함
코드가 짧음
성능이 느림
메모리 사용량이 많음
소량의 데이터
프로토타입
Parcelable 성능이 빠름
안드로이드 최적화
구현이 복잡함
(Kotlin은 간단)
대량의 데이터
실제 프로덕션
기본 타입 가장 빠름
구현 매우 간단
기본 타입만 가능 String, Integer 등
간단한 리스트
. . . . .
2) 선택 기준
(1) Serializable을 선택해야 할 때
빠른 프로토타이핑이 필요한 경우
② 전달할 데이터의 양이 적은 경우 (10개 이하)
③ 성능이 크게 중요하지 않은 화면 전환
④ 기존 Java 클래스를 활용해야 하는 경우
(2) Parcelable을 선택해야 할 때
대량의 데이터를 전달해야 하는 경우 (100개 이상)
② 성능이 중요한 프로덕션 앱
③ Kotlin을 사용하는 경우 (@Parcelize로 간단 구현)
④ 복잡한 객체 구조를 전달해야 하는 경우
(3) 기본 타입을 선택해야 할 때
① String, Integer 등 기본 타입만 전달하면 되는 경우
② 최고의 성능이 필요한 경우
③ 간단한 설정 값이나 ID 목록 전달

#5. 주의사항과 문제 해결
1) 흔히 발생하는 오류와 해결
(1) ClassCastException 발생
데이터를 받을 때 잘못된 타입으로 캐스팅하면 발생합니다.
// 잘못된 예
ArrayList<Subway> list = (ArrayList<Subway>) getIntent().getSerializableExtra("subway");
// null일 경우 NullPointerException 발생 가능

// 올바른 예 (안전한 캐스팅)
ArrayList<Subway> list = null;
Serializable serializable = getIntent().getSerializableExtra("subway");
if (serializable instanceof ArrayList) {
    list = (ArrayList<Subway>) serializable;
}
(2) TransactionTooLargeException 발생
Intent로 전달할 수 있는 데이터의 크기는 약 1MB로 제한되어 있습니다. 큰 데이터를 전달하려고 하면 이 오류가 발생합니다.
해결 방법 1 - 데이터를 분할하여 여러 번 전달
해결 방법 2 - 데이터베이스나 SharedPreferences에 저장 후 ID만 전달
해결 방법 3 - ViewModel이나 싱글톤 패턴 활용
. . . . .
2) 성능 최적화 팁
(1) 대용량 데이터 처리 방법
// 대용량 데이터는 ID만 전달하고 DB에서 조회
// 전송 Activity
val selectedIds = selectedItems.map { it.id }
intent.putIntegerArrayListExtra("selected_ids", ArrayList(selectedIds))

// 수신 Activity
val selectedIds = intent.getIntegerArrayListExtra("selected_ids")
val items = database.getItemsByIds(selectedIds)
(2) Kotlin에서 Parcelable 사용 시 플러그인 설정
// build.gradle.kts (Module)
plugins {
    id("kotlin-parcelize")
}
. . . . .
3) 실전 예제 - RecyclerView에서 선택한 항목 전달
// 데이터 클래스
@Parcelize
data class Product(
    val id: Int,
    val name: String,
    val price: Int
) : Parcelable

// RecyclerView에서 선택한 항목들을 다음 화면으로 전달
class ProductListActivity : AppCompatActivity() {
    private val selectedProducts = ArrayList<Product>()

    private fun goToCheckout() {
        val intent = Intent(this, CheckoutActivity::class.java)
        intent.putParcelableArrayListExtra("selected_products", selectedProducts)
        startActivity(intent)
    }
}

// CheckoutActivity에서 받기
class CheckoutActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_checkout)

        val products = intent.getParcelableArrayListExtra<Product>("selected_products")
        products?.let {
            displayProducts(it)
        }
    }
}

마무리
ArrayList 객체를 Intent로 전달하는 방법은 안드로이드 개발에서 매우 자주 사용되는 패턴입니다. 이 글에서 소개한 세 가지 방법 중 상황에 맞는 최적의 방법을 선택하면 됩니다.
핵심 요약
Serializable - 가장 간단하지만 성능이 낮음, 소량의 데이터에 적합
Parcelable - 안드로이드 최적화, 대량 데이터와 프로덕션 앱에 권장
기본 타입 메서드 - String, Integer 등 기본 타입 리스트에 최적
데이터 크기가 1MB를 초과하면 다른 방법 사용 (DB, ViewModel 등)
⑤ Kotlin에서는 @Parcelize 어노테이션으로 Parcelable을 쉽게 구현 가능
실제 프로젝트에서는 Kotlin + @Parcelize + Parcelable 조합을 사용하는 것을 권장합니다. 이 조합은 구현이 간단하면서도 뛰어난 성능을 제공하기 때문입니다. 데이터 전달은 안드로이드 앱의 기본이 되는 작업이므로, 이 글에서 소개한 방법들을 잘 이해하고 활용하시기 바랍니다!
긴 글 읽어주셔서 감사합니다.

끝.
반응형