Serializable vs Parcelable

2015-08-29

error

我們都知道在Android內如果要傳送資料必須透過Intent或Bundle

在送基本型態(int,String,boolean..)時應該沒有什麼爭議

但是如果要送一個 Object 呢?

這時你就有兩個選擇了,你可以使用
● Serializable
● Parcelable

稍微解釋一下這兩個interface

Serializable 是 Java 的 interface
Parcelable 是 Android 的 interface
在使用他們時,你的 Class 必須 implements 他們

既然都可以達到資料傳送的目的
那為什麼Android還要特地出一個 Parcelable 給大家使用呢?

當然是因為 performance 的問題
Serializable 在使用上非常方便
只需要 implements 他就結束了,但是
Serializable 在Java就一直被大家所詬病
他是利用反射來實例化物件
但這種方法會造成大量的temporary objects(臨時物件)
VM也要花時間對這些對象進行garbage collection(GC)

當然 Parcelable 就不是利用反射了
而是我們在 implement 他時就實作他的method
透過泛型直接給定他Class


下面有個簡單的Sample
讓我們實際測試看看兩者之間的效能落差



1.專案配置


很簡單,就一個Layout 與 Activity 與兩個 Model Object

error

2.Layout


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_marginBottom="20dp"
        android:padding="10dp"
        android:text="測試執行50000次的\nParcelable/Serializable效能差異"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:padding="10dp"
        android:text="Parcelable 所花時間(ms):"
        android:id="@+id/pTimeTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:padding="10dp"
        android:text="Serializable 所花時間(ms):"
        android:id="@+id/sTimeTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:textColor="#cc0000"
        android:padding="10dp"
        android:text="效能落差(ms):"
        android:id="@+id/parcelableTimeTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="執行測試"
        android:id="@+id/button"
        />
</LinearLayout>


3.Java Code


DataP

import android.os.Parcel;
import android.os.Parcelable;

public class DataP implements Parcelable{
    private int a;
    private String b;
    private boolean c;

    public DataP(int a, String b, boolean c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public boolean isC() {
        return c;
    }

    public void setC(boolean c) {
        this.c = c;
    }

    protected DataP(Parcel in) {
        a = in.readInt();
        b = in.readString();
    }

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

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

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

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

DataS

import java.io.Serializable;

public class DataS implements Serializable {
    private int a;
    private String b;
    private boolean c;

    public DataS(int a, String b, boolean c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public boolean isC() {
        return c;
    }

    public void setC(boolean c) {
        this.c = c;
    }
}

MainActivity
在兩個for迴圈內做5萬次的 put 與 get (單純模擬)
最後把執行時間相減來做出比較

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button button = (Button)findViewById(R.id.button);
        final TextView pTimeTv = (TextView)findViewById(R.id.pTimeTv);
        final TextView sTimeTv = (TextView)findViewById(R.id.sTimeTv);
        final TextView parcelableTimeTv = (TextView)findViewById(R.id.parcelableTimeTv);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle bundle = new Bundle();

                long pStart = System.currentTimeMillis();
                for(int i=0;i<50000;i++){
                    DataP p1 = new DataP(i,String.valueOf(i),true);
                    bundle.putParcelable("keyP" + i, p1);
                    DataP p2 = bundle.getParcelable("keyP"+i);
                }
                long pEnd = System.currentTimeMillis();
                long sStart = System.currentTimeMillis();
                for(int i=0;i<50000;i++){
                    DataS s1 = new DataS(i,String.valueOf(i),true);
                    bundle.putSerializable("keyS" + i,s1);
                    DataS s2 = (DataS)bundle.getSerializable("keyS"+i);
                }
                long sEnd = System.currentTimeMillis();

                long pSub = pEnd - pStart;
                long sSub = sEnd - sStart;
                long parcelableSub = (sSub>pSub)?(sSub-pSub):(pSub-sSub);

                pTimeTv.setText("Parcelable 所花時間(ms):"+pSub);
                sTimeTv.setText("Serializable 所花時間(ms):"+sSub);
                parcelableTimeTv.setText("效能落差(ms):"+parcelableSub);
            }
        });
    }
}


4.總結


從我的不專業測試得知結果為
創建5萬個物件(序/反列化)兩者之間時間差為0.7
Parcelable 大約是 Serializable 的兩倍

試想如果今天是10萬或20萬個物件呢,整體速度都會被拖慢!
你的App使用起來就會很卡頓!
所以還是多使用 Parcelable 吧!

兩者優缺點比較:

Serializable:
● 程式碼簡潔,閱讀容易
● 反序列化時需要強制轉型
● 速度較慢

Parcelable:
● 程式碼較複雜
● 速度較快,佔用資源較少

國外的說法是兩者之間效能差約10倍
error
個人是覺得沒那麼誇張
不過兩倍以上是有的
大家可以download sample code回去自己測試看看
歡迎將測試結果貼上來這裡~~