이번엔 레퍼런스가 된 글을 먼저 소개하고 시작하겠다.
안드로이드 - Serializable를 활용한 다른 액티비티에 객체(Object) 전달하기
두 개의 사용법을 비교하기 앞서, 대체 이 것들은 왜 필요한지? 비교가 필요한지 궁금해졌다.
안드로이드 앱을 개발할 때 우리는 하나의 액티비티에서 다른 액티비티로 데이터를 전달하기 위해 기본적으로 putExtra
를 이용한다.
데이터를 추가하며 데이터 전달을 하는데 전달할 데이터가 복잡한 클래스의 객체라면?
class Person{
private String name;
private int age;
public void setName(String name)
{
this.name = name;
}
public void setAge(int age)
{
this.age = age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
}
putExtra로는 어림도 없다.
그래서 이 때 필요한 것이 직렬화
이다. 한글로 번역해서 어색한 단어지만 영어로는 serialization
직렬화란? 자바 시스템 내부에서 사용되는 Object/Data를 외부의 자바 시스템에서도 사용할 수 있도록 byte 형태로 데이터를 변화는 기술이다.
즉, JVM의 메모리에 상주(Heap or Stack)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술이다.
직렬화가 있으면 역직렬화도 있다. 역직렬화도 간단하게 짚고 넘어가자.
역직렬화란? Byte로 변환된 data를 원래대로 Object/Data로 변환하는 기술이다. 즉, 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM에 상주시키는 형태다.
여기서 잠깐 OS의 기초로 돌아간다. 프로세스들끼리는 데이터를 주고 받을 수 없다 (= 메모리를 공유하지 않기 때문이다) 그래서 다른 Process에 데이터를 전달하기 위해 IPC(Inter Process Communication)를 사용하는데, IPC는 byte stream 전송이 가능하기 때문에 이 때! 직렬화가 필요하다.
(좀 멀리 돌아온 기분이지만 대충 기본을 짚었다고 생각하고) 앞서 예제인 Person 클래스를 보면, 변수 2개와 변수에 접근할 수 있는 멤버 함수 getter/setter가 정의되어 있는 클래스다. Person 클래스 안에 멤버 변수들은 연속된 메모리에 할당되지 않기 때문에 직렬화 객체가 될 수 없다.
이것들을 바이트 형태로 변환하기 위해선 먼저 메모리에 할당되어야 한다는 전제를 만족해야한다.
그래서 Java Interface인 Serialiazlbe로 해당 class가 직렬화 대상이라고 알려주는 marker interface다. 그러니깐 연속으로 메모리에 할당해! 하는..
어떠한 메서드도 가지지 않는 단순한 인터페이스라, 이 인터페이스로 직렬화하는 방법은 간단하다. Serializable를 상속만 하면 된다. 상속만 받으면 자동으로 직렬화가 처리된다.
단, 몇 가지 조건을 만족해야 한다.
serialVersionUID란? Serializable 클래스 버전을 기억하여 로드된 클래스와 직렬화 된 객체가 호환되는지 확인하는 속성.
+) 그리고 Serializable은 Reflection을 아용해 직렬화를 처리한다.
Reflection이란? 프로세스 동작 중에 사용되며 처리 과정 중에 많은 추가 객체를 생성.
그러나 이런 추가 객체를 생성하는 거 때문에 GC의 타겟이 되고 GC의 과도한 동작으로 인해 성능 저하 및 배터리 소모가 발생한다.
Parcelabe도 직렬화를 위한 또다른 인터페이스다. 다만, 표준 Java 인터페이스가 아니라 Android SDK의 인터페이스다.
Parcelable은 Reflection을 사용하지 않도록 설계되었다. Serializable과는 달리 직렬화 처리 방법을 개발자가 명시적으로 작성해야해서 자동으로 직렬화 처리를 위한 Reflection이 필요없다.
대신, Parcelabe은 직접 코드를 작성해야하는 만큼 보일러 플레이트 코드도 추가되고 새로운 기능을 추가하기도 힘듭니다. 즉, 갈수록 유지보수가 어렵고 가독성이 떨어지는 현상이 발생한다.
1. 속도
이 결과에 대해 유명한 사진이라 다들 아는 사실이겠지만 Parcelabe이 Serializable보다 훨씬 빠르다고 한다.
실험 결과표를 보면 Parcelable이 Serializable보다 10배 이상 빠르다는 것을 확인할 수 있다.
그러나, 한편으로는 이게 기본 Serializalbe을 써서 속도가 느린 결과가 나온 거라고 한다. Serializable에서 자동으로 처리되는 프로세스는 개발자가 writeObject()
와 readObject()
메서드를 구현해 대체할 수 있다.
이렇게 구현하고 제대로 working이 된다면 기본 사용법으로 쓴 Serializable 방식에서의 추가 객체(a.k.a 쓰레기)가 많이 생성되지 않는다고 한다..
이건 개인의 판단이겠지만 Serializable을 Parcelable과 같은 방식으로 구현하고 테스트해보면 다른 결과가 나온 다는 것을 볼 수 있다.
2. Reflection 사용 여부
Parcelable은 Reflection을 쓰지 않고 Serializable은 쓴다.
위에서 기본 Serializable이 parcelable보다 느리다고 결과가 나온 이유에는 Reflection 사용 여부가 크다. 이를 사용하냐 마냐에 따라 프로세스가 자동으로 처리하면서 추가 객체를 생성하냐가 따르기 때문이다.
3. 출처
Serializable은 표준 Java Interface고 Parcelable은 Android SDK 인터페이스이다.
Parcelable 공식 문서 : https://developer.android.com/reference/android/os/Parcelable
Parcelable은 개발자가 메서드를 직접 구현해야한다는 단점이 있지만 요즘은 애너테이션 하나로 해당 단점이 사라졌다.
plug in으로 id 'kotlin-parcelize'
을 추가하고 직렬화가 필요한 클래스에 @Parcelize
애너테이션을 추가하면 수많은 코드를 자동으로 추가해준다.