본문
안드로이드 리모트 서비스 만들기 #2. Parcelable
*이 글은 '안드로이드 리모트 서비스 만들기 #1. with AIDL'에 이은 글입니다.
AIDL을 사용하는 서비스간 통신에 있어서 데이터의(변수) 전송은 제한적이다. 특히 컴플렉스 타입을 전송하는데에는 Parcelable 인터페이스를 구현하여야 한다. 이때, Parcelable의 역할은 안드로이드 런타임에 객체의 직렬화(serialize) 과정을 도와주는 것이다. 물론 serializable을 사용하여 직렬화하고 전송할 수 있겠지만, 안드로이드에서는 공유메모리를 활용하는, IPC(Inter-Process Communication)통신에서의 효율성을 위하여 사용자가 내부정보에 대한 사항을 직접 명시함으로서, 자바 프로세서가 클래스 내부를 일일히 처리해야하는 오버헤드를 줄여준다.
우선 AIDL에서 사용되는 자료형에 대한 참고사항은 다음과 같다. (from 안드로이드 4 실무 바이블)
- AIDL은 String과 CharSequence를 지원한다.
- AIDL은 다른 AIDL 인터페이스도 주고받을 수있지만, import 구문으로 해당 AIDL 인터페이스를 알려줘야 한다. 임포트할 인터페이스가 같은 패키지에 있는 것이라고 해도 명시적으로 임포트해줘야 한다.
- AIDL은 android.os.Parcelable 인터페이스를 구현한 타입이면 무엇이든지 넘길수 있다. AIDL 파일에서 임포트해줘야 한다.
- AIDL은 java.util.List와 java.util.Map도 사용할 수 있지만 몇가지 제약 사항이 있다. 이 컬렉션에 넣을 수 있는 객체는 자바 기본형, String, CharSequence, android.os.Parcelable 뿐이다. List와 Map은 임포트하지않고도 사용할 수 있지만 Parcelable을 구현한 타입은 꼭 임포트해야한다.
- String을 제외한 비기본 타입은 방향 지시자가 있어야 한다. 방향 지시자는 in, out, inout이고 클라이언트 쪽에 중요하다. out은 서비스에서만 값을 할당한다는 말이고, inout은 클라이언트와 서버 모두 할당한다는 뜻이다.
미지원 컴플렉스 클래스를 만드는데에는, 다음과 같은 작업이 필요하다.
1. Parcelable 인터페이스를 구현하여 컴플렉스 클래스를 만든다. 이 인터페이스에는 writeToParcel()과 describeContents()가 선언되어 있어 이를 구현해 주어야 한다.
2. 컴플렉스 클래스 내에 android.os.Parcelable.Create 인터페이스를 구현하는 CREATOR라는 static final 필드를 구성한다. 이 인터페이스에는 createFromParcel()과 newArray()가 선언되어있어 이를 구현해주어야 한다.
3. 컴플렉스 클래스와 동일한 이름을 갖는 .aidl 파일을 만들고, java 파일과 같은 위치에 둔다.
1+2. Parcelable 인터페이스 구현 및 CREATOR 필드 구성
>Movement.java
package com.frontjang1.service_interface;
import android.os.Parcel;
import android.os.Parcelable;
public class Movement implements Parcelable{
public int x; public int y;
public static final Parcelable.Creator<Movement> CREATOR
= new Parcelable.Creator<Movement>() {
public Movement createFromParcel(Parcel in){
return new Movement(in);
}
@Override
public Movement[] newArray(int size) {
return new Movement[size];
}
};
public Movement(){ }
private Movement(Parcel in) {
readFromParcel(in);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(x); dest.writeInt(y);
}
public void readFromParcel(Parcel in){
x=in.readInt(); y=in.readInt();
}
@Override
public int describeContents() {
return 0;
}
}
위 클래스는 x, y 좌표를 전달하는 Movement 클래스이다. Movement()생성자에는 readInt()를 각각 수행하여 x값과 y값을 parcel로부터 불러온다. 그리고 writeToParcel()은 이와 반대로, writeInt()로 클래스상의 필드들을 parcel에 기록한다. describeContents()는 'Describe the kinds of special objects contained in this Parcelable's marshalled representation.' 라고 하는데 자주 사용되지는 않는다.
안드로이드 Parcelable 레퍼런스 페이지에는 readFromParcel이 없지만, 서비스 aidl가 java로 재생성 될 때 readFromParcel()을 요구하므로?, readFromParcel()을 만들어 이를 생성자에서 호출하면 좋다.(이때 기입 순서가 일치해야 한다) 이에 더하여 Movement() public 생성자를 요구하므로, public Movement(){}를 기입하는것이 좋다. CREATOR는 해당 parcel의 unmarshalling과정에 사용되는 것이므로 역시 필요하다. Movement array의 사이즈만큼 공간을 할당하고, parcel로부터 Movement 객체를 생성하는 과정을 확인할 수 있다.
3. 컴플렉스 클래스와 동일한 이름을 갖는 .aidl 파일을 만들기
>Movement.aidl
package com.frontjang1.service_interface;
parcelable Movement;
해당 aidl 파일은 개발자가 작성한 parcelable 구현 클래스가 어디에 위치해 있는지 AIDL처리기에게 지시해주는 역할을 한다.
http://developer.android.com/reference/android/os/Parcel.html
댓글