반응형
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; }
}
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
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);
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)
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());
}
}
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}")
}
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];
}
};
}
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
// 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)
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}")
}
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")
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")
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;
}
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)
// 전송 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")
}
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)
}
}
}
@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 조합을 사용하는 것을 권장합니다. 이 조합은 구현이 간단하면서도 뛰어난 성능을 제공하기 때문입니다. 데이터 전달은 안드로이드 앱의 기본이 되는 작업이므로, 이 글에서 소개한 방법들을 잘 이해하고 활용하시기 바랍니다!
긴 글 읽어주셔서 감사합니다.
끝.
끝.
반응형
'Development > Android' 카테고리의 다른 글
| [Android] Android Activity 생명주기와 실전 구현 방법 (기본) (0) | 2020.04.08 |
|---|---|
| [Android ] Android Intent Flag 완벽 가이드 - 화면 전환 제어 방법 (0) | 2020.04.08 |
| [Android] Android Activity 오류 해결 및 성능 최적화 방법 (0) | 2020.04.08 |
| [Android] Android Picasso vs Glide 이미지 라이브러리 비교와 선택 기준 (0) | 2019.10.01 |
| [Android] Android ViewModel과 LiveData 실전 구현 방법 (아키텍처 가이드) (0) | 2019.09.23 |