在Android中一个Activity跳转至另一个Activity或者启动Service、发送广播等都需要Intent,可以说Intent在Android中用途比较广泛,我们还可以通过Intent在跳转至下一个界面或者启动另一个组件时携带一些数据进行传递到下一个界面或者组件已达到传值的效果。不过在通常通过Intent传值都是传递一些某些具体类型的数据。具体代码如下:
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("name","_彼岸雨敲窗_");
intent.putExtra("age",25);
intent.putExtra("isBoy",true);
startActivity(intent);
这里通过Intent的putExtra()方法来添加具体类型(比如String、Int以及Boolean类型等)的数据,然后在SecondActivity接收传递过来的数据。具体代码如下:
getIntent().getStringExtra("name");
getIntent().getIntExtra("age", 0);
getIntent().getBooleanExtra("isBoy", true);
可以看到这种传值方式非常方便,但是也有一定的局限性,比如传递数据的类型比较多或者传递的数据量比较大的时候这种方式传递数据不是最优的选择。那么,有没有最优的传递复杂的数据类型的方式呢?还真有,可以通过自定义对象的方式,然后通过Serializable和Parcelable方式进行传递数据。下面就来看看如何在Intent中使用这两种方式进行传递数据吧。
Serializable是序列化的意思,它表示将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。如何让对象进行序列化呢?只需要在创建的对象类实现Serializable这个接口就可以了。代码如下:
public class Programmer implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private boolean boy;
// set 和 get 略
}
可以看到我们在Programmer类实现了Serializable的接口,Programmer类中的所有对象都可以实现了可序列化了。
然后在Intent传递数据时可以这样写,代码如下:
Intent intent = new Intent(this, SecondActivity.class);
Programmer programmer = new Programmer();
programmer.setName("_彼岸雨敲窗_");
programmer.setAge(25);
programmer.setBoy(true);
intent.putExtra("programmer_data", programmer);
startActivity(intent);
可以看到,这里还是使用Intent中的putExtra()方法来添加数据,不过这里不是添加某具体类型的数据,而是添加已经被序列化过实例对象的数据。
然后接下来在SecondActivity中获取传递过来的对象数据,代码如下:
Programmer programmer = (Programmer) getIntent().getSerializableExtra("programmer_data");
if (programmer != null) {
String name = programmer.getName();
int age = programmer.getAge();
boolean isBoy = programmer.isBoy();
}
可以看到这里取得数据使用的是getSerializableExtra()方法,该方法的作用就是通过传递过来的序列化对象强转成Programmer对象,然后调用对象的get()方法取出相应的数值。
Intent使用Serializable方式传递数据的原理:首先先将一个对象序列化成一个可以储存或者可以传输的状态,然后传递下一个界面时通过反序列化成一个新的对象,最后通过新的对象进行取值操作。
Parcelable是Android系统中特有的接口,它不像Serializable接口那样是Java语言自带的。Intent也使用Parcelable方式来传递对象的数据,不过它不同于Serializable方式将对象进行序列化,而是通过将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的传递数据类型。下面我们就来看看如何实现这个方式的数据传递,首先先创建一个对象,代码如下:
public class Programmer implements Parcelable {
private String name;
private int age;
private boolean boy;
protected Programmer(Parcel in) {
name = in.readString();
age = in.readInt();
boy = in.readByte() != 0;
}
public static final Creator<Programmer> CREATOR = new Creator<Programmer>() {
@Override
public Programmer createFromParcel(Parcel in) {
return new Programmer(in);
}
@Override
public Programmer[] newArray(int size) {
return new Programmer[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
parcel.writeByte((byte) (boy ? 1 : 0));
}
// set 和 get 略
}
从代码中可以看出,Parcelable实现的方式相对于Serializable要复杂一点,首先先让Programmer对象实现了Parcelable接口,然后重写describeContents()和writeToParcel()方法,其中describeContents()方法直接返回0就可以了,而writeToParcel()中我们需要调用Parcel对象的writeXX()方法依次把字段写入。除了这两个方法之外,我们还要实现一个名为CREATOR的匿名内部类,在这里创建了Programmer.Creator的泛型接口,并将泛型类型设为Programmer,接着在该接口重写createFromParcel()和newArray()方法,而在createFromParcel()方法中,
我们需要创建Programmer对象进行返回,并使用Parcel对象的readXX()方法读取刚才在writeToParcel()写入的字段,需要注意的是,这里读取的顺序一定和刚才写入的顺序相同。而在newArray()方法中需要实现就比较简单了,只需要直接返回Programmer对象数组大小即可。
然后在Intent传递数据时可以这样写,代码如下:
Intent intent = new Intent(this, SecondActivity.class);
Programmer programmer = new Programmer();
programmer.setName("_彼岸雨敲窗_");
programmer.setAge(25);
programmer.setBoy(true);
intent.putExtra("programmer_data", programmer);
startActivity(intent);
可以看到,这里还是使用Intent中的putExtra()方法来添加数据。
然后接下来在SecondActivity中获取传递过来的对象数据,代码如下:
Programmer programmer = (Programmer) getIntent().getParcelableExtra("programmer_data");
if (programmer != null) {
String name = programmer.getName();
int age = programmer.getAge();
boolean isBoy = programmer.isBoy();
}
可以看到这里取得数据使用的是getParcelableExtra()方法来获取传递过来的Programmer对象,然后调用对象的get()方法取出相应的数值。
Parcelable相对于Serializable的使用相对复杂一些;
Parcelable的传输效率相对Serializable高很多;
Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。
Intent携带信息的大小其实是受Binder限制。数据以Parcel对象的形式存放在Binder传递缓存中。如果数据或返回值比传递buffer大,则此次传递调用失败并抛出TransactionTooLargeException异常。Binder传递缓存有一个限定大小,通常是1Mb。但同一个进程中所有的传输共享缓存空间。多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。在使用Intent传递数据时,1Mb并不是安全上限。因为Binder中可能正在处理其它的传输工作。不同的Android设备和系统版本,这个上限值也可能会不同。
如果是要传递较大的数据的话,建议使用EventBus来代替Intent传递较大的数据。
———————— The end ————————
码字不易,如果您觉得这篇博客写的比较好的话,可以赞赏一杯咖啡吧~~