头图

Android Activity 传递Parcelable对象

前面我们知道了启动activity的时候可以传递一些参数。Activity的跳转时可以传递Parcelable对象。

Parcelable对象和Serializable不一样。实现了Parcelable接口的类并不会被系统序列化。
接下来我们用一个例子看看如何使用这一接口。

使用例子

先准备数据,然后传送Parcelable对象。

数据准备

先设计一个类实现Parcelable接口。前面我们使用Serializable的时候,类只要实现Serializable接口即可,不需要额外的操作。但用Parcelable接口会需要开发者多做一些工作。

Parcelable接口在android.os包里,与Serializable不同。我们必须明确认识这一点。
官方给出的一个使用例子。

public class MyParcelable implements Parcelable {
      private int mData;
 
      public int describeContents() {
          return 0;
      }
 
      public void writeToParcel(Parcel out, int flags) {
          out.writeInt(mData);
      }
 
      public static final Parcelable.Creator<MyParcelable> CREATOR
              = new Parcelable.Creator<MyParcelable>() {
          public MyParcelable createFromParcel(Parcel in) {
              return new MyParcelable(in);
          }
 
          public MyParcelable[] newArray(int size) {
              return new MyParcelable[size];
          }
      };
 
      private MyParcelable(Parcel in) {
          mData = in.readInt();
      }
}

可以看到,强制使用了一个Parcelable.Creator对象。里面的方法我们暂时不管也不修改。
重点关注私有构造器MyParcelable(Parcel inwriteToParcel方法。

官方例子中,私有构造器接收一个Parcel对象,然后从中读出一个int。而writeToParcel方法中,把mData写入Parcel对象中。
这写入和读出操作就是我们开发者需要特别关心的地方。

之前使用intent.putExtra方法的时候会传入一个String类型的key(键),用于标示传入的数据。
但在官方的例子中,我们只看到了一个int。而writeInt方法也没有指定key。系统如何区分出各个参数呢?

我们自定义一个类DataParcel,实现Parcelable接口。as自动在里面生成了CREATOR


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

public class DataParcel implements Parcelable {
    private int number;
    private String str1;
    private String str2;
    private String noSave = "[不传送的字符串]";
    
    // getter setter ...

    public String info() {
        return "number: "+number+", str1: "+str1+", str2: "+str2+", noSave: "+noSave;
    }

    protected DataParcel(Parcel in) {
        number = in.readInt();
        str1 = in.readString();
        str2 = in.readString();
    }

    public DataParcel(int number, String str1, String str2, String noSave) {
        this.number = number;
        this.str1 = str1;
        this.str2 = str2;
        this.noSave = noSave;
    }

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

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

    };

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(number);
        dest.writeString(str1);
        dest.writeString(str2);
    }
}

可以看到我们有1个int和3个String。公开构造器需要传入这4个属性。

writeToParcel方法中,按顺序写入了int和2个String。私有构造器中,按顺序读出了int和2个String。

noSave并没有被写入和读出。拿来做对比。info()方法是拿来打印信息的。

传送Parcelable对象

现在我们的类已经设计好了,传送对象试试。

把DataParcel对象交给intent。

DataParcel dataParcel = new DataParcel(100, "s1", "s2", "改变这个字符串看看能否被传递");
intent.putExtra(SendParamsDemo.K_PARCEL, dataParcel);

被打开的Activity接收传入的对象。

DataParcel dataParcel = intent.getParcelableExtra(K_PARCEL);

log中打印出发送和传入的对象信息。

D/rustAppMainActivity: goSendParamsDemo: parcel obj: com.rustfisher.tutorial2020.act.DataParcel@d8ce985
D/rustAppMainActivity: goSendParamsDemo: parcel obj: number: 100, str1: s1, str2: s2, noSave: 改变这个字符串看看能否被传递

D/rustAppSendParamsDemo: gotInput: parcel obj: com.rustfisher.tutorial2020.act.DataParcel@d90a3a6
D/rustAppSendParamsDemo: gotInput: number: 100, str1: s1, str2: s2, noSave: [不传送的字符串]

从log中我们可以看出,发送的对象和接收到的对象并不是同一个对象。但我们指定的那3个属性是相同的。

总结

至此,我们了解了如何使用Parcelable这个接口。
ParcelParcelable是Android IPC中使用到的容器和工具。大家可以了解一下Binder机制

一般认为,普通情况下Parcelable性能上会优于Serializable
Serializable涉及到序列化,系统会通过反射的方法来获取信息。相对而言比较耗资源。
Parcel并不涉及序列化机制。它是为了高性能IPC传输设计的。因此,Parcel并不适合用来永久化存储数据。

实际工作中,我们可以根据业务需要,综合开发时间成本和应用性能要求,来选择使用Parcelable或者Serializable

软件工程师

5 声望
1 粉丝
0 条评论
推荐阅读
Android 自定义View - 柱状波形图 wave view
前言柱状波形图是一种常见的图形。一个个柱子按顺序排列,构成一个波形图。柱子的高度由输入数据决定。如果输入的是音频的音量,则可得到一个声波图。在一些音频软件中,我们也可以左右拖动声波,来改变音频的播...

AnRFDev阅读 375

如何用3D流体实现逼真水流效果?
华为应用市场在2022年HDC大会期间发布了一款3D水流主题,基于华为HMS Core Scene Kit服务能力,展现立体灵动的水流岛屿,可跟随用户指尖实现实时流体波动效果,既趣味又解压。

HMSCore1阅读 2.1k

Android桌面图标快捷方式
长按桌面图标实现快捷方式最早是iOS提供的功能,而Android最早在Android 7.1版本也提供了对这方面的支持,于是在短时间内,像微信,支付宝,头条等流量级应用都提供了这方面的支持,如下图。 

xiangzhihong3阅读 593评论 2

安卓逆向之破解某成人APP播放次数限制
某成人水果APP非VIP用户存在播放次数限制,每天只能播放3次。超过3次需要购买VIP。 由于过于贫穷,于是抽空,对其安卓APP进行了逆向分析,最终成功破解了其播放次数限制。

悖论2阅读 261

封面图
2022 年终总结|致敬即将过去的,匆忙而又虐心的一年...
本文参与了 SegmentFault 思否年度征文「一名技术人的 2022」,欢迎正在阅读的你也加入。 时间,总是过的这么快,快得让人猝不及防,眨眼又是一年的末...似乎儿时的文章中,对于时间的流逝,描述的最多的便是:白...

贺biubiu1阅读 1.1k

封面图
读懂 gradle dependencies
不过在使用 dependencies 时有一些细节之前一直没有搞清楚,遂研究了一下部分细节。本文整体参考 gradle 官方文档,大家感兴趣也可以自己深入研究下。

云音乐技术团队1阅读 459

封面图
Android实现RecyclerView嵌套流式布局
新建Activity文件RecyclerViewActivity.class {代码...} Activity页面布局activity_recycler_view.xml {代码...}

似水流年1阅读 793

软件工程师

5 声望
1 粉丝
宣传栏