7

Android Activity 传递Parcelable对象

 2 years ago
source link: https://segmentfault.com/a/1190000040709459
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Android Activity 传递Parcelable对象

发布于 9 月 19 日

前面我们知道了启动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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK