Android 의 직렬 화 방식

머리말
실제 개발 과정 에서 우 리 는 종종 서열 화 대상 의 수요 가 있다.안 드 로 이 드 에 서 는 SerializableParcelable 인 터 페 이 스 를 사용 하 는 두 가지 방식 으로 대상 의 직렬 화 를 실현 할 수 있다.
Serializable 방식
Serializable 인 터 페 이 스 는 자바 가 제공 하 는 직렬 화 인터페이스 이다.실제로 이것 은 빈 인터페이스 로 표시 역할 만 한다.진정한 직렬 화 와 반 직렬 화 과정 은 모두 시스템 에 의 해 이 루어 지기 때문에 사용 하기에 편리 하 다.다음은 Serializable 인터페이스의 사용 을 보 여 주 는 간단 한 예 입 니 다.
Serializable 인 터 페 이 스 를 실현 하 는 클래스:
public class Reader implements Serializable {
    private static final long serialVersionUID = 1L;

    private int readerId;
    private String name;

    public Reader(int readerId, String name) {
        this.readerId = readerId;
        this.name = name;
    }

    @Override
    public String toString() {
        return "readerId:"+readerId+" name:"+name;
    }

    public int getReaderId() {
        return readerId;
    }
    public void setReaderId(int readerId) {
        this.readerId = readerId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Reader 클래스 에 다음 코드 가 있 습 니 다.
private static final long serialVersionUID = 1L;

이 코드 는 직렬 화 된 대상 에 serialVersionUID 값 을 기록 하 는 역할 을 합 니 다.이 롱 값 은 대상 이 속 한 클래스 구조 에 변화 가 있 는 지 를 표시 할 수 있다.역 직렬 화 를 진행 할 때 직렬 화 대상 의 serialVersionUID 값 과 Reader 류 의 serialVersionUID 값 이 일치 해 야 성공 할 수 있 습 니 다.일반적으로 우 리 는 이 값 을 1L 으로 지정 하면 된다.
서열 화 과정:
//   
ObjectOutputStream objectOutStream=null;
try {
    Reader reader=new Reader(1,"Tom");
    objectOutStream=new ObjectOutputStream(new FileOutputStream("reader.txt"));
    objectOutStream.writeObject(reader);
} catch (IOException e) {
    e.printStackTrace();
}finally{
    //    
    if(objectOutStream!=null){
        try {
            objectOutStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

핵심 코드 는 이 네 마디 입 니 다.
ObjectOutputStream objectOutStream=null;
Reader reader=new Reader(1,"Tom");
objectOutStream=new ObjectOutputStream(new FileOutputStream("reader.txt"));
objectOutStream.writeObject(reader);
ObjectOutputStream 대상 의 writeObject 방법 을 통 해 우 리 는 Reader 대상 을 reader.txt 파일 에 편리 하 게 쓸 수 있 음 을 알 수 있다.실제로 이 파일 이름 은 접미사 이름 이 없어 도 마음대로 정의 할 수 있 습 니 다.역 직렬 화 할 때 같은 파일 이름 을 사용 하면 됩 니 다.
역 직렬 화 과정:
//    
ObjectInputStream objectInStream=null;
try {
    objectInStream=new ObjectInputStream(new FileInputStream("reader.txt"));
    try {
        Reader reader=(Reader) objectInStream.readObject();
        System.out.println(reader);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
} catch (IOException e) {
    e.printStackTrace();
}finally{
    //    
    if(objectInStream!=null){
        try {
            objectInStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

핵심 코드 는 이 세 마디 입 니 다.
ObjectInputStream objectInStream=null;
objectInStream=new ObjectInputStream(new FileInputStream("reader.txt"));
Reader reader=(Reader) objectInStream.readObject();
ObjectInputStream 대상 의 readObject 방법 을 통 해 reader.txt 이라는 파일 에서 Reader 대상 의 내용 을 복원 할 수 있 습 니 다(강제 전환 이 필요 합 니 다).주의해 야 할 것 은 이 절 차 를 통 해 우 리 는 원래 의 Reader 대상 의 내용 을 회복 할 수 밖 에 없다 는 것 이다.그러나 본질 적 으로 이런 방식 으로 얻 은 리더 대상 은 기 존 리더 대상 과 같은 것 이 아니다.
Serializable 인 터 페 이 스 를 실현 한 클래스 에서 구성원 변 수 는 기본 유형 을 포함 할 수 있 을 뿐만 아니 라 Serializable 인 터 페 이 스 를 실현 한 다른 대상 도 포함 할 수 있다.시스템 은 직렬 화 를 진행 할 때 각 대상 의 직렬 화 과정 을 순서대로 집행 한다.
또 알 아야 할 것 은 클래스 의 정적 변 수 는 직렬 화 되 지 않 는 다 는 것 이다.정적 변 수 는 클래스 에 속 하기 때문에 특정한 대상 에 속 하지 않 습 니 다.이 밖 에 transient 키워드 에 의 해 수 식 된 변 수 는 직렬 화 되 지 않 습 니 다.
Parcelable 방식
직렬 화 효율 에 대한 수요 에서 안 드 로 이 드 도 자신 만 의 직렬 화 인터페이스 Parcelable 을 제공 했다.이 인터페이스의 사용 방식 은 Serializable 보다 훨씬 복잡 하지만 더 높 은 성능 을 얻 을 수 있다.다음은 간단 한 예 를 들 어 보 겠 습 니 다.
Parcelable 클래스 구현:
public class Book implements Parcelable {
    private int bookId;
    private String name;

    public Book(int bookId,String name) {
        this.bookId=bookId;
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(name);
    }

    public static final Parcelable.Creator CREATOR=new 
            Parcelable.Creator(){
        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    //      Book       
    private Book(Parcel source){
        bookId=source.readInt();
        name=source.readString();
    }
    //getter、setter  
    ........
}

Book 류 는 Parcelable 인 터 페 이 스 를 실현 하려 면 writeToParceldescribeContents 이라는 두 가지 방법 을 실현 해 야 한다.writeToParcel 은 데 이 터 를 직렬 화 하 는 데 사용 되 고 Parcel 대상 의 일련의 write 방법 을 통 해 구성원 변 수 를 점차적으로 직렬 화 시킨다.describeContent 방법 은 보통 0 으로 돌아 가면 됩 니 다.이것 은 설명 정보 입 니 다.
반면 북 의 반 서열 화 과정 은 정적 상수 Parcel.Creator 으로 이 루어 졌 다.우 리 는 익명 내부 류 의 방식 을 통 해 Parcel.Creator 대상 을 실례 화 했 고 createFromParcelnewArray 이라는 두 가지 방법 을 다시 썼 다.newArray 방법 에서 우 리 는 간단하게 북 배열,즉 return new Book[size] 으로 돌아 가면 된다.createFromParcel 방법 은 대상 의 반 서열 화 과정 을 진정 으로 실현 했다.저 희 는 Parcel 에서 구성원 변수의 내용 을 한 번 씩 읽 고 개인 적 인 구조 방법 으로 Book 대상 을 예화 합 니 다.이 대상 의 내용 은 서열 화 된 대상 의 내용 과 일치한다.물론 Serializable 과 마찬가지 로 이렇게 얻 은 북 대상 은 원래 의 대상 과 같은 것 이 아니다.주의해 야 할 것 은 데 이 터 를 읽 는 순서 가 데 이 터 를 쓰 는 순서 와 같 아야 한 다 는 것 이다.그렇지 않 으 면 역 직렬 화 는 반드시 실패 할 것 이다.그 다음으로 Parcel.Creator 대상 은 public 또는 protected 으로 만 수식 할 수 있 고 그렇지 않 으 면 반 직렬 화 역시 실패 할 것 이다.
이상 은 간단 한 예 일 뿐 북 류 의 구성원 변 수 는 모두 기본 데이터 형식 입 니 다.하지만 우리 류 에는 다른 대상 이 포 함 될 때 가 많다.이 는 Parcelable 멤버 를 어떻게 서열 화 하 는 지,Parcelable 멤버 를 어떻게 반 서열 화 하 는 지 에 관 한 간단 한 설명 이다.
상대 적 으로 복잡 한 Parcelable 예제:
public class Reader implements Parcelable {
    private int readerId;
    private String name;

    private Book book;

    public Reader(int readerId, String name, Book book) {
        this.readerId = readerId;
        this.name = name;
        this.book = book;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(readerId);
        dest.writeString(name);
        dest.writeParcelable(book,0);
    }

    public static final Parcelable.Creator CREATOR=new
            Parcelable.Creator(){
        @Override
        public Reader createFromParcel(Parcel source) {
            return new Reader(source);
        }

        @Override
        public Reader[] newArray(int size) {
            return new Reader[size];
        }
    };

    //      Reader       
    private Reader(Parcel source){
        readerId=source.readInt();
        name=source.readString();
        //              
        book=source.readParcelable(Thread.currentThread().getContextClassLoader());
    }
    //getter、setter  
    .........
}

Reader 클래스 에 북 멤버 가 있 고 북 은 Parcelable 인 터 페 이 스 를 실현 한 것 을 볼 수 있 습 니 다.writeToParcel 방법 에서 우 리 는 다음 과 같은 문 구 를 사용 하여 북 멤버 들 을 직렬 화 시 켰 다.
dest.writeParcelable(book,0);

두 번 째 매개 변 수 는 일반적으로 0 에 전달 하면 된다.역 직렬 화 과정 에서 우 리 는 다음 과 같은 문 구 를 사용 했다.
//              
book=source.readParcelable(Thread.currentThread().getContextClassLoader());

우리 가 Book 대상 을 읽 을 때 ClassLoader 이 들 어 왔 습 니 다.이것 은 현재 스 레 드 의 입 니 다.이 인자 가 들 어 오지 않 으 면 시스템 에서 Book 에 대응 하 는 종 류 를 찾 을 수 없 으 며,이 로 인해 역 직렬 화 에 실패 할 수 있 습 니 다.
두 가지 방식 의 비교
위의 예 를 통 해 우 리 는 Serializable 이라는 방식 을 사용 하 는 것 이 상당히 간단 하고 구체 적 인 세부 사항 은 모두 시스템 에 의 해 도 급 되 었 다 는 것 을 뚜렷하게 느 낄 수 있다.하지만 편 의 는 대 가 를 치 러 야 한다.Serializable 을 사용 하 는 비용 은 매우 크다.잦 은 IO 작업 이 필요 하기 때문에 안 드 로 이 드 가 Parcelable 을 출시 한 이유 이기 도 하 다.Parcelable 은 사용 하기에 더욱 번 거 롭 지만 더 좋 은 성능 을 얻 을 수 있다.
따라서 메모리 직렬 화 와 관련 된 장면 에서 Intent 를 통 해 직렬 화 대상 을 전달 할 경우 Parcelable 을 사용 하 는 것 을 권장 합 니 다.그리고 대상 을 저장 장치 에 직렬 화하 거나 직렬 화 된 대상 을 네트워크 를 통 해 전송 하 는 등 장면 에서 Serializable 을 사용 하 는 것 을 권장 합 니 다.

좋은 웹페이지 즐겨찾기