序列化Serializable和Parcelable的理解和區(qū)別

本文出自 “阿敏其人” 簡書博客,轉(zhuǎn)載或引用請注明出處。

一、android為什么要序列化?什么是序列化,怎么進(jìn)行序列化

why

為什么要了解序列化?—— 進(jìn)行Android開發(fā)的時候,無法將對象的引用傳給Activities或者Fragments,我們需要將這些對象放到一個Intent或者Bundle里面,然后再傳遞。

what

什么是序列化 —— 序列化,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)。序列化后的對象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲到本地。

how

怎么通過序列化傳輸對象?

Android中Intent如果要傳遞類對象,可以通過兩種方式實現(xiàn)。

  • 方式一:Serializable,要傳遞的類實現(xiàn)Serializable接口傳遞對象,
  • 方式二:Parcelable,要傳遞的類實現(xiàn)Parcelable接口傳遞對象。

Serializable(Java自帶):
Serializable是序列化的意思,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)。序列化后的對象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲到本地。

Parcelable(android 專用):
除了Serializable之外,使用Parcelable也可以實現(xiàn)相同的效果,
不過不同于將對象進(jìn)行序列化,Parcelable方式的實現(xiàn)原理是將一個完整的對象進(jìn)行分解,
而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實現(xiàn)傳遞對象的功能了。

實現(xiàn)Parcelable的作用

1)永久性保存對象,保存對象的字節(jié)序列到本地文件中;

2)通過序列化對象在網(wǎng)絡(luò)中傳遞對象;

3)通過序列化在進(jìn)程間傳遞對象。

選擇序列化方法的原則

1)在使用內(nèi)存的時候,Parcelable比Serializable性能高,所以推薦使用Parcelable。

2)Serializable在序列化的時候會產(chǎn)生大量的臨時變量,從而引起頻繁的GC。

3)Parcelable不能使用在要將數(shù)據(jù)存儲在磁盤上的情況,因為Parcelable不能很好的保證數(shù)據(jù)的持續(xù)性在外界有變化的情況下。盡管Serializable效率低點,但此時還是建議使用Serializable 。

應(yīng)用場景

需要在多個部件(Activity或Service)之間通過Intent傳遞一些數(shù)據(jù),簡單類型(如:數(shù)字、字符串)的可以直接放入Intent。復(fù)雜類型必須實現(xiàn)Parcelable接口。

二、利用java自帶的Serializable 進(jìn)行序列化的例子

弄一個實體類 Person,利用Java自帶的Serializable進(jìn)行序列化

package com.amqr.serializabletest.entity;
import java.io.Serializable;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:16
 * Describe: Describe Text
 */
public class Person implements Serializable{
    private static final long serialVersionUID = 7382351359868556980L;
    private String name;
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

使用,MainActivity和SecondActivity結(jié)合使用

MainActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Person;
/**
 * 進(jìn)行Android開發(fā)的時候,我們都知道不能將對象的引用傳給Activities或者Fragments,
 * 我們需要將這些對象放到一個Intent或者Bundle里面,然后再傳遞。
 *
 *
 * Android中Intent如果要傳遞類對象,可以通過兩種方式實現(xiàn)。
 * 方式一:Serializable,要傳遞的類實現(xiàn)Serializable接口傳遞對象,
 * 方式二:Parcelable,要傳遞的類實現(xiàn)Parcelable接口傳遞對象。
 *
 * Serializable(Java自帶):
 * Serializable是序列化的意思,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)。序列化后的對象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲到本地。
 *
 * Parcelable(android 專用):
 * 除了Serializable之外,使用Parcelable也可以實現(xiàn)相同的效果,
 * 不過不同于將對象進(jìn)行序列化,Parcelable方式的實現(xiàn)原理是將一個完整的對象進(jìn)行分解,
 * 而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實現(xiàn)傳遞對象的功能了。
 要求被傳遞的對象必須實現(xiàn)上述2種接口中的一種才能通過Intent直接傳遞。
 */
public class MainActivity extends Activity {
    private TextView mTvOpenNew;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.mTvOpenNew).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent open = new Intent(MainActivity.this,SecondActivity.class);
                Person person = new Person();
                person.setName("一去二三里");
                person.setAge(18);
                // 傳輸方式一,intent直接調(diào)用putExtra
                // public Intent putExtra(String name, Serializable value)
                open.putExtra("put_ser_test", person);
                // 傳輸方式二,intent利用putExtras(注意s)傳入bundle
                /**
                Bundle bundle = new Bundle();
                bundle.putSerializable("bundle_ser",person);
                open.putExtras(bundle);
                 */
                startActivity(open);
            }
        });
    }
}

SecondActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Person;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 11:56
 * Describe: Describe Text
 */
public class SecondActivity extends Activity{
    private TextView mTvDate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        mTvDate = (TextView) findViewById(R.id.mTvDate);
        Intent intent = getIntent();
        // 關(guān)鍵方法:getSerializableExtra ,我們的類是實現(xiàn)了Serializable接口的,所以寫這個方法獲得對象
        // public class Person implements Serializable
        Person per = (Person)intent.getSerializableExtra("put_ser_test");
        //Person per = (Person)intent.getSerializableExtra("bundle_ser");
        mTvDate.setText("名字:"+per.getName()+"\\n"
                +"年齡:"+per.getAge());
    }
}
Serializable的序列化.gif

Serializable 到此完成

三、android專用的Parcelable的序列化的例子

我們寫一個實體類,實現(xiàn)Parcelable接口,馬上就被要求

1、復(fù)寫describeContents方法和writeToParcel方法

2、實例化靜態(tài)內(nèi)部對象CREATOR,實現(xiàn)接口Parcelable.Creator 。

也就是,隨便一個類實現(xiàn)了Parcelable接口就一開始就會變成這樣子

Parcelable方式的實現(xiàn)原理是將一個完整的對象進(jìn)行分解,而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實現(xiàn)傳遞對象的功能了。

public class Pen implements Parcelable{
    private String color;
    private int size;
    protected Pen(Parcel in) {
        color = in.readString();
        size = in.readInt();
    }
    public static final Creator<Pen> CREATOR = new Creator<Pen>() {
        @Override
        public Pen createFromParcel(Parcel in) {
            return new Pen(in);
        }
        @Override
        public Pen[] newArray(int size) {
            return new Pen[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(color);
        dest.writeInt(size);
    }
}

系統(tǒng)已經(jīng)幫我們做了很多事情,我們需要做的很簡單,就寫寫我們自己需要的構(gòu)造方法,寫一下私有變量的get和set

大概變成這樣子:

package com.amqr.serializabletest.entity;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:52
 * Describe: Describe Text
 */
public class Pen implements Parcelable{
    private String color;
    private int size;
    
    // 系統(tǒng)自動添加,給createFromParcel里面用
    protected Pen(Parcel in) {
        color = in.readString();
        size = in.readInt();
    }
    public static final Creator<Pen> CREATOR = new Creator<Pen>() {
        /**
         *
         * @param in
         * @return
         * createFromParcel()方法中我們要去讀取剛才寫出的name和age字段,
         * 并創(chuàng)建一個Person對象進(jìn)行返回,其中color和size都是調(diào)用Parcel的readXxx()方法讀取到的,
         * 注意這里讀取的順序一定要和剛才寫出的順序完全相同。
         * 讀取的工作我們利用一個構(gòu)造函數(shù)幫我們完成了
         */
        @Override
        public Pen createFromParcel(Parcel in) {
            return new Pen(in); // 在構(gòu)造函數(shù)里面完成了 讀取 的工作
        }
        //供反序列化本類數(shù)組時調(diào)用的
        @Override
        public Pen[] newArray(int size) {
            return new Pen[size];
        }
    };
    
    @Override
    public int describeContents() {
        return 0;  // 內(nèi)容接口描述,默認(rèn)返回0即可。
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(color);  // 寫出 color
        dest.writeInt(size);  // 寫出 size
    }
    // ======分割線,寫寫get和set
    //個人自己添加
    public Pen() {
    }
    //個人自己添加
    public Pen(String color, int size) {
        this.color = color;
        this.size = size;
    }
    
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
}

其實說起來Parcelable寫起來也不是很麻煩,在as里面,我們的一個實體類寫好私有變量之后,讓這個類繼承自Parcelable,接下的步驟是:

1、復(fù)寫兩個方法,分別是describeContents和writeToParcel

2、實例化靜態(tài)內(nèi)部對象CREATOR,實現(xiàn)接口Parcelable.Creator 。 以上這兩步系統(tǒng)都已經(jīng)幫我們自動做好了

3、自己寫寫我們所需要的構(gòu)造方法,變量的get和set

實現(xiàn)自Parcelable實體Bean已經(jīng)寫好了,接下來我們結(jié)合MainActivity和ThirdActivity來使用以下:

MainActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.amqr.serializabletest.entity.Pen;
import com.amqr.serializabletest.entity.Person;
/**
 * 進(jìn)行Android開發(fā)的時候,我們都知道不能將對象的引用傳給Activities或者Fragments,
 * 我們需要將這些對象放到一個Intent或者Bundle里面,然后再傳遞。
 *
 *
 * Android中Intent如果要傳遞類對象,可以通過兩種方式實現(xiàn)。
 * 方式一:Serializable,要傳遞的類實現(xiàn)Serializable接口傳遞對象,
 * 方式二:Parcelable,要傳遞的類實現(xiàn)Parcelable接口傳遞對象。
 *
 * Serializable(Java自帶):
 * Serializable是序列化的意思,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)。序列化后的對象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲到本地。
 *
 * Parcelable(android 專用):
 * 除了Serializable之外,使用Parcelable也可以實現(xiàn)相同的效果,
 * 不過不同于將對象進(jìn)行序列化,Parcelable方式的實現(xiàn)原理是將一個完整的對象進(jìn)行分解,
 * 而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實現(xiàn)傳遞對象的功能了。
 要求被傳遞的對象必須實現(xiàn)上述2種接口中的一種才能通過Intent直接傳遞。
 */
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.mTvOpenNew).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent open = new Intent(MainActivity.this, SecondActivity.class);
                Person person = new Person();
                person.setName("一去二三里");
                person.setAge(18);
                // 傳輸方式一,intent直接調(diào)用putExtra
                // public Intent putExtra(String name, Serializable value)
                open.putExtra("put_ser_test", person);
                // 傳輸方式二,intent利用putExtras(注意s)傳入bundle
                /**
                 Bundle bundle = new Bundle();
                 bundle.putSerializable("bundle_ser",person);
                 open.putExtras(bundle);
                 */
                startActivity(open);
            }
        });
        // 采用Parcelable的方式
        findViewById(R.id.mTvOpenThird).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent mTvOpenThird = new Intent(MainActivity.this,ThirdActivity.class);
                Pen tranPen = new Pen();
                tranPen.setColor("big red");
                tranPen.setSize(98);
                // public Intent putExtra(String name, Parcelable value)
                mTvOpenThird.putExtra("parcel_test",tranPen);
                startActivity(mTvOpenThird);
            }
        });
    }
}

ThirdActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Pen;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:47
 * Describe: Describe Text
 */
public class ThirdActivity extends Activity{
    private TextView mTvThirdDate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
//        Intent intent = getIntent();
//        Pen pen = (Pen)intent.getParcelableExtra("parcel_test");
        Pen pen = (Pen)getIntent().getParcelableExtra("parcel_test");
        mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
        mTvThirdDate.setText("顏色:"+pen.getColor()+"\\n"
                            +"大小:"+pen.getSize());
    }
}

Parcelable的方式.gif

完成,Serializable 和Parcelable 這兩種方式都介紹完成了。接下說一說對比

四、Serializable 和Parcelable的對比

android上應(yīng)該盡量采用Parcelable,效率至上

編碼上:

Serializable代碼量少,寫起來方便

Parcelable代碼多一些

效率上:

Parcelable的速度比高十倍以上

serializable的迷人之處在于你只需要對某個類以及它的屬性實現(xiàn)Serializable 接口即可。Serializable 接口是一種標(biāo)識接口(marker interface),這意味著無需實現(xiàn)方法,Java便會對這個對象進(jìn)行高效的序列化操作。

這種方法的缺點是使用了反射,序列化的過程較慢。這種機(jī)制會在序列化的時候創(chuàng)建許多的臨時對象,容易觸發(fā)垃圾回收。

Parcelable方式的實現(xiàn)原理是將一個完整的對象進(jìn)行分解,而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型,這樣也就實現(xiàn)傳遞對象的功能了

五、demo

http://pan.baidu.com/s/1dDLGWKD

參考

Android中Parcelable接口用法
http://www.cnblogs.com/renqingping/archive/2012/10/25/Parcelable.html

Android系統(tǒng)中Parcelable和Serializable的區(qū)別
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0204/2410.html

第一行代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容