Android/App개발2009. 7. 20. 20:23
Parcelable Object 만들기 (1) Android Life 

2009/07/17 16:24

복사http://blog.naver.com/visualc98/74522627


[Parcel Class?]

 

Android의 핵심 중에서 Binder Driver라는 녀석이 있습니다.
Linux Kernel의 driver로 되어 있고, IPC이긴 하지만 기존의 IPC와는 살짝 다른 녀석 입니다.

 

저도 어떻게 만들었는지는 잘 모릅니다만, 
shared memory를 통하여 오버헤드도 적고 프로세스 사이에 비동기로 호출도 이루어 진다고 합니다.
그리고 Binder는 기존 IPC처럼 데이터만 전달 하는게 아니라,
하나의 프로세스에서 다른 프로세스로 Object를 넘길 수도 있게끔 설계 되어 있습니다.
(물론 Serialize 기술을 사용하면 Object도 주고 받을 순 있지요.)

 

Binder를 통해서 넘기는 메세지 (data 와 object references) 는 
Parcel 클래스에 저장이 되어서 넘어가게 됩니다. Parcel은 메세지 컨테이너인 셈이죠.

Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport.

Parcel 클래스는 고성능 IPC 전송을 가능하게 끔 설계가 되어 있기 때문에,

모든 객체에 대해서 평범하게 serialization하지 않습니다. 
그래서 모든 Object들을 Binder를 통해 주고 받을 수는 없습니다.

 


[Parcelable Interface]

 

Primitive Type과 Primitive Array Type은 기본적으로 parcelable 합니다.

뭐 그냥 일반 데이터인거죠.
그리고 
Parcelable Interface를 implements한 클래스가 (당연히) parcelable 합니다.

 

오늘 우리가 할 일이 바로 이 Parcelable Interface를 사용하여
parcelable Object를 만드는 일 인 것이죠.

사실 parcelable한 type들이 많이 있습니다만, 나머지는 잘 모르겠군요... 어렵습니다.
여튼 오늘은 parcelable Object를 만드는 것만 생각 합시다.

 


[Parcelable Rect]

 

Rect 클래스야 다들 쉽게 만드실 겁니다.
left, top, right, bottom 4개의 필드만 있으면 되죠.


integer든 float이든 상관 없습니다만....
Android에는 Rect 클래스의 float 버전이 RectF 클래스 라고 따로 되어 있기 때문에,

저는 integer로 만들겁니다.


public class Rect {
    public int left;
    public int top;
    public int right;
    public int bottom;
}


뭐 아주 간단 합니다. 그냥 C에서의 구조체 수준이네요.
이것을 parcelable하게 바꾸어 봅시다.

 

Step 1.


public class Rect implements Parcelable {
    public int left;
    public int top;
    public int right;
    public int bottom;
    
    public int describeContents() {
        return 0;
    }
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(left);
        dest.writeInt(top);
        dest.writeInt(right);
        dest.writeInt(bottom);
    }
}


Parcelable을 implements하게 되면 꼭 추가해야 한다는 메소드 두 개도 같이 넣었습니다.
내용도 채워 봤어요.

 

describeContents() 메소드는 일단 건너뛰고...
writeToParcel() 메소드는 Parcel에 데이터를 쓰는 부분 입니다.
그냥 무작정 쓰면 됩니다. 전 아무 생각 없이 순서대로 그냥 썼습니다.

 

그럼 이제 에러도 없으니 parcelable한 Rect 클래스가 되었느냐... 라고 한다면 아직 아닙니다.
쓰는건 있는데 읽는건 없네요...

 

Parcel로 부터 값을 읽어 오기 위해서는 Parcelable.Creator Interface 가 필요합니다.

 


[Parcelable.Creator Interface]

 

Parcel 에서 Parcelable 클래스의 인스턴스를 만들 때
CREATOR라는 static field를 찾아서 실행 합니다.
CREATOR는 
Parcelable.Creator<T> type 으로 만들어져야 하는데 
이건 선언과 동시에 반드시 initialize 되어야 합니다.

 

클래스 따로 만들어서 initialize 하기도 쉽지 않습니다.
그냥 익명 클래스로 만들어 버립시다.

 

Step 2.


public class Rect implements Parcelable {
    public int left;
    public int top;
    public int right;
    public int bottom;
    
    public int describeContents() {
        return 0;
    }
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(left);
        dest.writeInt(top);
        dest.writeInt(right);
        dest.writeInt(bottom);
    }
    
    public static final Parcelable.Creator<Rect> CREATOR new Creator<Rect>() {
        public Rect createFromParcel(Parcel source) {
            Rect r   = new Rect();
            r.left   = source.readInt();
            r.top    = source.readInt();
            r.right  = source.readInt();
            r.bottom = source.readInt();
            return r;
        }
        public Rect[] newArray(int size) {
            return new Rect[size];
        }
    };
}


Parcelable.Creator<T> 클래스는 createFromParcel() 과 newArray() 메소스가 필요 합니다.

 

newArray() 메소드도 일단 넘어가고...
createFromParcel() 메소드를 보면 리턴이 Rect입니다.
그래서 Parcel에서 값을 읽어 새로운 Rect 인스턴스를 리턴 하는 구조로 만들면 끝입니다.

 

readInt()를 했는데, 이것은 writeToParcel() 메소드에서 썼던 순서대로 읽어 오는 것입니다.
쓸 때는 무작정 썼지만 읽을 때는 조심스럽게 읽어야하죠.

 

이제 비로소 parcelable Rect 클래스를 만들었습니다.
그냥 별거 없군요...

 


[Appendix]

 

위에서 describeContents() 메소드와 newArray() 메소드는 그냥 넘어 갔었습니다.
네... 뭐 사실 잘 모르기도 합니다만, 
그냥 보통 parcelable Object를 만드는데에 크게 중요한 부분은 아니지요. 아하하...

 

describeContents() 에서는 어떤 특별한 객체를 포함하고 있는지에 대한 설명을
리턴값으로 표현 하는 것이라고 보면 됩니다.
bit mask 형식의 integer를 리턴 하며,
값을 체크 할 때 bit mask 체크를 해서 어떤 것들이 들어 있는지 알 수 있습니다.

 

현재 사용하는 플래그는 Parcelable.CONTENTS_FILE_DESCRIPTOR (0x00000001) 
하나 밖에 정의 되어 있지 않습니다.
소스를 다 뒤져 보지 않아서 또 어떤 값들이 쓰이는지는 확인 해보지 못했네요...

 

newArray() 메소드는 그냥 배열로 만들어서 리턴 하는 겁니다.
Parcel.createTypedArray() 메소드에서 newArray() 메소드를 호출 하는 걸 확인 했습니다.
나중에 createTypedArray() 메소드를 사용 할 일이 있다면 newArray()가 호출이 되는 것이지요.

Posted by 삼스

댓글을 달아 주세요

  1. 태양이 바다에 미광을 비추면,나는 너를 생각한다.

    2013.07.12 01:41 [ ADDR : EDIT/ DEL : REPLY ]