六、Android中 IPC 机制(3)之序列化---Parcelable 接口

为什么要使用 Parcelable 接口:

    和 Serializable 接口类似,都是为一个类实现序列化和可序列化功能,以让该类的对象可以通过 Intent 和 Binder 传递。

Parcelable 接口和 Serializable 接口的区别:

    1. Serializable 接口是 java 提供的原生序列化接口,使用起来简单但是由于它的序列化和反序列化过程需要大量的 I/O 操作,所以开销很大。

    2. Parcelable 接口是 Android 提供的序列化接口,因此更适合用在 Android 平台上,也是 Android 推荐的序列化方式。虽然它使用起来稍微比较麻烦但是它的效率很高,因此我们首选使用 Parcelable。(因为有 AS,其实现在也很方便,都是自动导入。)

Parcelable 接口和 Serializable 接口的使用场景:

    1. Parcelable 主要用于内存序列化上,比如当我们使用 Intent 或者 Binder 传递对象时,优先使用这种方式。

    2. Serializable 主要用于将对象序列化到存储设备上或者通过网络传输对象时。 

Parcelable 接口使用示例:

// Girl.java  实现了 Parcelable 接口的类
package com.cfm.parcelableactivity;

public class Girl implements Parcelable {
    private String mName;
    private String mDream;

    public Girl(String name, String dream) {
        mName = name;
        mDream = dream;
    }

    protected Girl(Parcel in) {
        mName = in.readString();
        mDream = in.readString();
    }

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

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

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }

    public String getDream() {
        return mDream;
    }

    public void setDream(String dream) {
        mDream = dream;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mName);
        dest.writeString(mDream);
    }
}
// User.java 实现了 Parcelable 接口的类,并包含实现了 Parcelable 接口的类的对象
package com.cfm.parcelableactivity;

public class User implements Parcelable {
    private int mId;
    private String mName;
    private String mDream;
    private Girl mGirl;

    public User(int id, String name, String dream, Girl girl) {
        mId = id;
        mName = name;
        mDream = dream;
        mGirl = girl;
    }

    /**
     * 反序列化过程。从序列化后的对象中创建原始对象。
     */
    private User(Parcel in) {
        mId = in.readInt();
        mName = in.readString();
        mDream = in.readString();
        mGirl = in.readParcelable(Thread.currentThread().getContextClassLoader());
    }

    public static final Creator<User> CREATOR = new Creator<User>() {

        /**
         *  从序列化的对象中创建原始对象。也就是反序列化过程。
         */
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        /**
         * 创建指定长度的原始对象数组。
         */
        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public int getId() {
        return mId;
    }

    public void setId(int id) {
        mId = id;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }

    public String getDream() {
        return mDream;
    }

    public void setDream(String dream) {
        mDream = dream;
    }

    public Girl getGirl() {
        return mGirl;
    }

    /**
     *  返回当前对象的内容描述。
     * @return 如果含有文件描述符,返回1;否则返回0。几乎所有情况都返回0.
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     *  将当前对象写入序列化结构中,也就是序列化过程。
     * @param flags 有两种值:0或1。为 1 时标识当前对象需要作为返回值返回,不能立即释放资源;几乎所有情况都返回0。

     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mId);
        dest.writeString(mName);
        dest.writeString(mDream);
        dest.writeParcelable(mGirl, 0);
    }
}
// FirstActivity.java 
package com.cfm.parcelableactivity;

public class FirstActivity extends AppCompatActivity {

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

        Button button = findViewById(R.id.first_btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                intent.putExtra("cfmtest", new User(1, "cfm", "open source", new Girl("ym", "Become Better and Better")));
                startActivity(intent);
            }
        });
    }
}
// SecondActivity.java 
package com.cfm.parcelableactivity;

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        User user = getIntent().getParcelableExtra("cfmtest");
        Log.d("cfmtest-SecondActivity", "mId: " + user.getId());
        Log.d("cfmtest-SecondActivity", "mName: " + user.getName());
        Log.d("cfmtest-SecondActivity", "mDream: " + user.getDream());
        Log.d("cfmtest-SecondActivity", "mGirl.name: " + user.getGirl().getName());
        Log.d("cfmtest-SecondActivity", "mGirl.dream: " + user.getGirl().getDream());
    }
}

// output
cfmtest-SecondActivity: mId: 1
cfmtest-SecondActivity: mName: cfm
cfmtest-SecondActivity: mDream: open source
cfmtest-SecondActivity: mGirl.name: ym
cfmtest-SecondActivity: mGirl.dream: Become Better and Better

    这里 FirstActivity 通过 Intent 将实现了 Parcelable 接口的 User 传送给 SecondActivity,可以看到 SecondActivity 成功收到并打印出了 User 对象的属性。

    可以看到通过 Parcelable 接口实现对象的序列化和反序列化过程主要三步:

    1. 序列化过程

        由 wirteToParcel(Parcel dest, int flags) 方法完成,最终是通过 Parcel 中的一系列 write 方法来完成。(使用 AS,会自动帮我们生成并实现这个方法。)

    2. 反序列化过程

        由 CREATOR 来完成,其内部标明了如何创建序列化对象和数组,并通过 Parcel 的一系列 read 方法来完成反序列化过程。

    3. 内容描述

        由 describeContents() 方法来完成,仅当当前对象中存在文件描述符时,返回 1;其余几乎都是返回 0。

        注意:我们在 User(Parcel in),也就是对象的反序列化过程调用方法中,由于 Girl 是另一个可序列化对象,所以它的反序列化过程需要传递当前线程的上下文类加载器。

mGirl =in.readParcelable(Thread.currentThread().getContextClassLoader());

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值