Serializable vs Parcelable

Author Avatar
Aaron Von 8月 31, 2017

Effective Android 系列

最近项目中在死磕性能,之前也大致总结了一个性能调优的大纲。光说不练假把式,既然 Java 有 Effective Java,那我也就写一篇 Effective Android 的系列文章,以记录我的死磕之路。

今天看到一位国外博主的一篇对比 SerializableParcelable 性能的文章,还附上了一个多设备对比的条形图。OMG,性能能有 10x 倍的提升?天下能有这等好事?不过本着求真的态度,还是写了一段测试代码来验证一下。这样一来,事情就变得有趣了。

先抛结论

有一定性能优势,但是完全没有那么悬殊。

测试设备: Google Pixel based on Oero。

全局图

1.全局图

放大图

2.放大图

Show Me the Code

  • SerializableComputer.java
public class SerializableComputer implements Serializable {
    private String brand;
    private String price;
    private int year;
    private double screenSize;
    private String resolution;
    private int usbPorts;
    private int batterySize;
    private ArrayList<String> serialNum;

    public SerializableComputer(String brand, String price, int year, double screenSize, String resolution,
                                int usbPorts, int batterySize, ArrayList<String> serialNum) {
        this.brand = brand;
        this.price = price;
        this.year = year;
        this.screenSize = screenSize;
        this.resolution = resolution;
        this.usbPorts = usbPorts;
        this.batterySize = batterySize;
        this.serialNum = serialNum;
    }
}
  • ParcelableComputer.java
public class ParcelableComputer implements Parcelable {
    private String brand;
    private String price;
    private int year;
    private double screenSize;
    private String resolution;
    private int usbPorts;
    private int batterySize;
    private ArrayList<String> serialNum;

    public ParcelableComputer(String brand, String price, int year, double screenSize, String resolution,
                              int usbPorts, int batterySize, ArrayList<String> serialNum) {
        this.brand = brand;
        this.price = price;
        this.year = year;
        this.screenSize = screenSize;
        this.resolution = resolution;
        this.usbPorts = usbPorts;
        this.batterySize = batterySize;
        this.serialNum = serialNum;
    }

    protected ParcelableComputer(Parcel in) {
        brand = in.readString();
        price = in.readString();
        year = in.readInt();
        screenSize = in.readDouble();
        resolution = in.readString();
        usbPorts = in.readInt();
        batterySize = in.readInt();
        in.readStringList(serialNum);
    }

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

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

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(brand);
        dest.writeString(price);
        dest.writeInt(year);
        dest.writeDouble(screenSize);
        dest.writeString(resolution);
        dest.writeInt(usbPorts);
        dest.writeInt(batterySize);
        dest.writeStringList(serialNum);
    }
}
  • MainActivity.java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "Aaron";
    private static final String BUNDLE_KEY = "BUNDLE_KEY";

    private Button serializableBtn;
    private Button parcelableBtn;

    private SerializableComputer mSerializableComputer;
    private ParcelableComputer mParcelableComputer;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        serializableBtn = (Button) findViewById(R.id.serializable_btn);
        parcelableBtn = (Button) findViewById(R.id.parcelable_btn);
        serializableBtn.setOnClickListener(mOnClickListener);
        parcelableBtn.setOnClickListener(mOnClickListener);
        initData();
    }

    private void initData() {
        String brand = "Mac";
        String price = "$2000";
        int year = 2017;
        double screenSize = 15.0;
        String resolution = "2880 x 1800";
        int usbPorts = 4;
        int batterySize = 5000;
        Random random = new Random(System.currentTimeMillis());
        ArrayList<String> serialNums = new ArrayList<>();
        for (int i = 0; i < 10; ++i) {
            serialNums.add(String.valueOf(random.nextInt()));
        }

        mSerializableComputer = new SerializableComputer(brand, price, year, screenSize, resolution, usbPorts, batterySize, serialNums);
        mParcelableComputer = new ParcelableComputer(brand, price, year, screenSize, resolution, usbPorts, batterySize, serialNums);
    }

    View.OnClickListener mOnClickListener = v -> {
        switch (v.getId()) {
            case R.id.serializable_btn: {
                for (int i = 0; i < 500; ++i) {
                    long start = System.nanoTime();
                    for (int j = 0; j < 10; ++j) {
                        Bundle bundle = new Bundle();
                        bundle.putSerializable(BUNDLE_KEY, mSerializableComputer);
                        SerializableComputer serializableComputer = (SerializableComputer) bundle.getSerializable(BUNDLE_KEY);
                    }
                    Log.d(TAG, "serializable: " + (System.nanoTime() - start));
                }
                break;
            }
            case R.id.parcelable_btn: {
                for (int i = 0; i < 500; ++i) {
                    long start = System.nanoTime();
                    for (int j = 0; j < 10; ++j) {
                        Bundle bundle = new Bundle();
                        bundle.putParcelable(BUNDLE_KEY, mParcelableComputer);

                        ParcelableComputer parcelableComputer = bundle.getParcelable(BUNDLE_KEY);
                    }
                    Log.d(TAG, "parcelable:   " + (System.nanoTime() - start));
                }
                break;
            }
            default: {
                break;
            }
        }
    };
}

All in All

虽然没有别人测出来 10x 倍的性能提升,或许和设备、Android 版本、甚至是写的代码有关系,不过至少我们也可以定性的得出一个结论,Parcelable 确实会比 Serializable 性能更好一些,不过这也是用更大的代码复杂度换来的。所以,代码只是一个工具,如果是为了快速开发和更低的维护成本,选择 Serializable 也未尝不可。如果死磕性能的话,Parcelable 又会是一个相对更好的选择。