안드로이드 프로그래밍 시 액티비티(Activity) 간에 객체를 전달하는 방법을 정리.
들어가며...
안드로이드 프로그래밍을 하다 보면 액티비티 간에 데이터를 전달해야 하는 경우가 종종 있다. 이때 데이터가 원시 타입의 변수들이라면 별다른 추가 조치 없이 쉽게 처리할 수 있지만 참조 타입의 객체라면 조금 손을 봐야 한다. 직렬화된 객체만 Bundle에 추가할 수 있기 때문이다.
Trindex 앱에서도 액티비티 간 객체를 전달하는 부분이 있다. 그것을 예시로 액티비티 간 객체 데이터 전달 방법을 정리해 본다.
액티비티 전환 전 송신 데이터 준비
Trindex 앱을 시작하면 가장 먼저 스플래시 액티비티가 시작되며 로고를 1~2초간 보여준다. 이때의 시간을 낭비하지 않기 위해 백그라운드에서 앱에 사용되는 기초 데이터 수집하도록 처리했다. 그런데 해당 데이터가 정작 본격적으로 사용될 곳은 메인 액티비티이기 때문에 수집한 데이터를 넘겨줘야 한다. 그래서 다음과 같이 메인 액티비티를 시작하기 전 인텐트에 송신 데이터들을 추가했다.
위 코드를 보면 settings와 dataManager가 모두 참조 타입 객체임에도 원시 타입 변수를 넘길 때처럼 putExtra() 메서드를 사용하는 것을 볼 수 있다. 이는 두 클래스를 Serializable과 Parcelable로 각각 직렬화해 주었기 때문에 가능한 것이다.
Serializable로 직렬화하는 방법
Serializable은 Java SDK에서 지원하는 직렬화 인터페이스이다. 앞서 등장한 settings 객체의 클래스 선언부에서는 다음과 같이 해당 인터페이스를 implements 해 주고 있다.
이렇게 선언하고 나면 Settings 클래스의 인스턴스는 직렬화가 가능한 객체로 인식되어 Bundle에 추가할 수 있게 된다. 그런데 이때 주의해야 할 것이 있다. Settings 클래스의 멤버 변수들 중 참조 타입의 변수들이 직렬화되어 있는가를 확인하는 것이다.
만약 참조 타입의 멤버 변수들이 직렬화된 객체가 아니라면 해당 객체의 클래스 역시 직렬화 시켜주거나 혹은 직렬화 동작과 관련된 두 메서 writeObject(), readObject()에서 별도의 처리를 해 주어야 한다.
Settings 클래스에 사용된 참조 타입의 멤버 변수는 ArrayList<String>과 String인데,
운이 좋게도 두 객체 모두 직렬화되어 있다. 따라서 추가로 직렬화 작업이 필요한 클래스는 없어 보인다. 이외 원시 타입의 변수들은 별다른 선언 없이도 기본적으로 직렬화된 상태라고 보면 된다.
참고로 위와 같이 변수 앞에 transient 키워드를 사용하게 되면 직렬화에서 의도적으로 배제시킬 수 있다. 전환될 액티비티에서 필요가 없거나 아니면 보안상 전달하면 안 되는 데이터에 사용하면 된다.
Parcelable로 직렬화하는 방법
Parcelable은 안드로이드 SDK에서 지원하는 직렬화 인터페이스이다. Serializable의 가장 큰 단점은 직렬화 비용이 너무 크다는 것인데, Parcelable은 상대적으로 가볍다. 따라서 안드로이드에서는 Parcelable 사용을 권장한다. 참고로 Serializable에 비해 10배 정도 좋은 성능을 보인다고 한다.
앞서 전송 대상으로 등장했던 또 다른 객체 dataManger는 Parcelable을 사용하여 직렬화하고 있다. 멤버로 사용되고 있는 객체 가운데 직렬화되지 않은 객체는 IndicatorData, CommodityData, PeriodData, EventData로 무려 네 개나 된다. 이 클래스들은 나중에 다시 언급될 예정이다.
Parcelable을 implements 하게 되면 생성자와 두 개의 메서드를 재정의 해 주어야 하고, 한 개의 정적 인스턴스를 만들어야 한다. 먼저 재정의 해 주어야 하는 두 개의 메서드를 보자.
describeContents() 메서드는 안드로이드 스튜디오에 의해 자동완성된 상태에서 굳이 수정할 필요가 없으니 그대로 둔다.
writeToParcel() 메서드에서는 인수로 넘겨받은 Parcel 인스턴스에 DataManager 클래스의 멤버 객체들을 하나씩 저장해 주어야 한다. 객체의 클래스에 따라 사용되는 writeXXX() 메서드가 조금씩 다른 것을 알 수 있다.
그다음은 생성자를 재정의하는 부분이다.
넘겨받은 Parcel 인스턴스를 이용해 값을 읽어오고, 멤버 변수들을 초기화하는 코드를 작성해 준다. 이곳 역시 각 클래스에 따라 값을 읽어오는 방법이 약간씩 차이가 있음을 알 수 있다.
마지막으로 DataManager 클래스에 추가해 주어야 하는 정적 인스턴스다. 굳이 수정해 줄 필요가 없는 부분이므로 안드로이드 스튜디오의 자동완성 기능을 사용한 뒤 그대로 두면 된다.
마지막으로 앞서 언급했던 멤버 객체들 중 직렬화되지 않은 클래스 네 개에 대해서도 각각 Parcelable 인터페이스를 implements 하고 필요한 내용들을 채워서 직렬화해 주어야 한다. 그래야만 액티비티 이동 후에도 누락되는 값 없이 온전한 데이터를 받아볼 수 있다.
액티비티 전환 후 데이터 수신
이제 전환된 액티비티에서 데이터를 잘 전달받고, 사용해 주기만 하면 되는데, 보통 액티비티의 onCreate() 메서드에서 데이터 수신부를 작성해 준다. Trindex 앱에도 메인 액티비티의 onCreate() 내 적당한 자리에 다음과 같은 데이터 수신 코드가 있다.