Serializable và Parcelable trong Android

1. Serializable

1.1 Serializable là gì Serialization là quá trình chuyển các cấu trúc dữ liệu và các đối tượng thành một định dạng có thể lưu trữ được (vào file, in-memory buffer, hoặc truyền qua network), sau đó có thể phục hồi lại các cấu trúc dữ liệu và đối tượng như ban đầu, trên cùng hoặc khác môi trường.

Để 1 đối tượng được áp dụng cơ chế tuần tự hóa trong Java, đối tuợng đó phải được cài đặt interface Serialiable trong gói java.io và cả trong các đối tượng con của đối tuợng này. Đây là một giao diện trống, không có method nào cần cài đặt.

Thuật toán Serialization sẽ thực hiện các công việc sau:

  • Ghi xuống các siêu dữ liệu (metadata) về class (ví dụ như tên của class, version của class, tổng số các field của class,….) , của đối tượng đó.

  • Ghi đệ quy các thông tin class cho tới khi nó gặp class Object.

  • Ghi các dữ liệu của các đối tượng

Tuần tự hóa có ba mục đích chính sau

  • Cơ chế ổn định: Nếu luồng được sử dụng là FileOuputStream, thì dữ liệu sẽ được tự động ghi vào tệp.

  • Cơ chế sao chép: Nếu luồng được sử dụng là ByteArrayObjectOuput, thì dữ liệu sẽ được ghi vào một mảng byte trong bộ nhớ. Mảng byte này sau đó có thể được sử dụng để tạo ra các bản sao của các đối tượng ban đầu.

  • Nếu luồng đang được sử dụng xuất phát từ một Socket thì dữ liệu sẽ được tự động gửi đi tới Socket nhận, khi đó chương trình nhận sẽ quyết định phải làm gì đối với dữ liệu nhận được (giải mã để có được dữ liệu của đối tượng)

1.2 Tại sao lại cần đến Serialization?

  • Một hệ thống enterprise điển hình thường có các thành phần nằm phân tán rải rác trên các hệ thống và mạng khác nhau. Trong Java mọi thứ đều được miêu tả như là một object. Nếu 2 thành phần Java cần liên lạc với nhau, ta cần phải có một cơ chế để chúng trao đổi dữ liệu. Serialization được định nghĩa cho mục đích này, và các thành phần Java sẽ sử dụng giao thức (protocol) này để truyền các object qua lại với nhau.

  • Có thể dùng trao đối dữ liệu giữa 2 hệ thông khác nhau sử dụng thuật tóan tuần tự hóa mà không phụ thuộc vào nền tảng giữa chúng.

2. Parcelable

2.1 Parcelable là gì Parcelable thường được sử dụng để gửi dữ liệu (dạng Object) giữa các activity với nhau thông qua Bunble gửi cùng Intent.

Để làm điều này 1 đối tượng phải được cài đặt giao diện Parcelable và ghi đè phương thức writeToParcel() trong lớp đó. Trong phương thức này triển khai ghi tất cả dữ liệu có trong lớp tới Parcel, tiếp theo triển khai một đối tuợng static final Parcelable.Creator để giải tuần tự tái tạo lại Java Object.

Theo các kỹ sư google, sử dụng đối tượng được cài đặt Parcelable sẽ chạy nhanh hơn đáng kể so với việc sử dụng Serializable. Một trong những lý do cho việc này là lớp này đuợc sử dụng rõ ràng về quá trình đọc ghi tuần tự thay vì sử dụng sự ánh xạ (reflection) để suy ra nó do đó mã đã được tối ưu hóa và tạo ra ít đối tuợng rác hơn cho mục đích này.

Tuy nhiên, việc thực hiện Parcelable không nhanh chóng và đơn giản như triển khai Serialization, phải triển khai một số lượng mã đáng kể để phục vụ cho điều này.

Ví dụ:

public class DemoParcelable implements Parcelable {
    private String userName;
    private String passwork;

    protected DemoParcelable(Parcel in) {
        userName = in.readString();
        passwork = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(userName);
        dest.writeString(passwork);
    }

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

    public static final Creator<DemoParcelable> CREATOR = new Creator<DemoParcelable>() {
        @Override
        public DemoParcelable createFromParcel(Parcel in) {
            return new DemoParcelable(in);
        }

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

Sau đó đưa đối tượng sau khi được đổ dữ liệu vào Bundle để truyền theo Intent tới Activity khác.

DemoParcelable obj = new DemoParcelable();
obj.setUserName = "quyet";
obj.setPasswork = "123";
Bundle b = new Bundle();
b.putParcelable("key", obj);
Intent i = new Intent(mContext, DemoActivity.class);
i.putExtras(b);
mContext.startActivity(i);

Để nhận về đối tượng vừa được gửi đi, bên Activity đích triển khai mã sau:

Bundle b = getIntent().getExtras();
DemoParcelable obj = (DemoParcelable) b. getParcelable("key");

3. Ưu nhược điểm

3.1 So sánh tốc giữa Parcelable và Serializable Phương pháp chung dùng để test: Đều sử dụng cùng 1 đối tượng nhưng triển khai cài đặt 2 lớp giao diện Serializable và Parcelable. Sau đó đối tượng được gửi qua Activity khác thông qua Bundle được gửi kèm Intent. Cuối cùng tính thời gian mà Activity đích nhận được đối tượng sau khi triển khai 2 giao diện.

3.2 So sánh tốc giữa Parcelable và Serializable Serializable:

  • Ưu điểm:

    • Cực kì dễ triển khai, ít yêu cầu kèm theo

    • Có thể ghi đối tượng xuống dạng tệp tin để lưu trữ xuống ổ đĩa, và có thể đọc ở nhìu hệ thống khác nhau

  • Nhược điểm:

    • Nó có tốc độ chậm, sinh ra nhiều đối tượng rác (garbage )

    • Nó rất khó để bảo trì (maintain) nếu bạn thay đổi cấu trúc của class.

Parcelable:

  • Ưu điểm:

    • Nó nhanh hơn Serializable

    • Dễ dàng đánh phiên bản cho đối tượng

    • Kiểm soát được dữ liệu tuần tự

  • Nhược điểm:

    • Nó phụ thuộc vào nên tảng (hiện tại phương thức này chỉ áp dụng cho android)

    • Vì chỉ tồn tại trong vòng đời của Activity nên dữ liệu không được ghi xuống file

    • Triển khai khó khăn hơn. Cấu trúc dữ liệu của Object thay đổi là cần thay đổi 1 trình tự đọc và ghi của phương thức.

4. Kết luận

Nếu bạn chỉ cần truyền dữ liệu giữa các Activity thì Parcelable là giải pháp tối ưu nhất vì tốc độ thực thi của nó.

Nếu bạn muốn lưu trữ sao chép hoặc truyền dữ liệu qua mạng thì Serializable cho thấy sự vượt trội của mình. Vì Serializable không phụ thuộc vào nền tảng nên nó dễ dàng truyền được dữ liệu từ nền tảng này qua nền tảng khác.

Hai giao diện đều có ưu và nhược điểm riêng, phụ thuộc vào bài toán được yêu cầu chúng ta sẽ sử dụng chúng 1 cách hợp lý.

Tham khảo