为什么要用 Intent 传递数据
当我们想要在两个 Activity 间传递数据时,我们会很自然的想到要用 Intent 的 putExtra 方法来传递数据。但是为什么一定要用 Intent 传递数据呢?
1. 复用性强、解耦
我们会发现,intent 在很多的组件中都出现过。如,启动 Activity, 启动服务, 传递广播。我们会经常性的利用 Intent 在这些组件之间传递信息,进行通信。所以,高度的复用性,和简便的使用方法,使 Activity 间解耦,肯定是我们使用它的理由。
2. 进程间通信
在启动 Activity 的时候,是需要通过系统服务 AMS(ActivityManagerService)注册,才能有生命周期的回调的,在这一过程中,intent 是全程参与的,所以在启动 Activity 的过程中,intent 已经跨越两次进程了。而且,我们创建 Activity 时候,是可以创建一个运行在新进程的 Activity 的。并且,我们也可以利用 intent 启动一些系统软件。上述这些操作,全都是跨进程通信的,Intent 就具有这样的能力。这也是我们使用 Intent 的一个原因。具体Activity启动过程
进程-分割多道程序,避免在内存并发执行时出乱子。在不同进程间内存是不共享的。
怎么传输的
上一节,我们说过,启动 Acitvity 时是要跨进程的,所以问题就变成了如何跨进程通信。在 Android 中我们是通过 AIDL 来实现的。而 AIDL 跨进程通信只支持的数据类型是:
1. Java 的原生类型,如int,boolean,long,float…
2. String 和CharSequence
3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型
4. AIDL 自动生成的接口 需要导入(import)
5. 实现android.os.Parcelable 接口的类. 需要导入(import)。
那么 Intent 是怎么实现的呢,我们一起来看一下:
public class Intent implements Parcelable, Cloneable
原来是实现了 Parcelable 接口。我们再往下看一下,稍后再来谈一下 Parcelable 。
public Intent putExtra(String name, String value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putString(name, value);
return this;
}
哦哦,原来数据都是放到 Bundle 中的。
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
public static final Bundle EMPTY;
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
}
public void putString(@Nullable String key, @Nullable String value) {
unparcel();
mMap.put(key, value);
}
Bundle 中也实现了 Parcleable
,而且用的是 Map 用来装载数据的。
Parcelable
Parcel 提供了一套机制,可以将序列化之后的数据写到一个共享内存当中,其他进程可以通过这块共享区读出数据并反序列话成对象。
进程间的数据传递是通过其中的内存共享区来实现的
下面我们就来实现通过 intent 来传递对象:
public class Usr implements Parcelable {
private String name;
private int age;
public Usr() {
}
protected Usr(Parcel in) {
name = in.readString();
age = in.readInt();
}
//读取接口
public static final Creator<Usr> CREATOR = new Creator<Usr>() {
@Override
public Usr createFromParcel(Parcel in) {
return new Usr(in);
}
@Override
public Usr[] newArray(int size) {
return new Usr[size];
}
};
//内容描述接口
@Override
public int describeContents() {
return 0;
}
//写入接口函数,打包
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}
我们实现 Parcelable 接口,重写其中的方法,就可以了。在 Android Studio 中实现起来其实是很方便的。
Usr usr = new Usr();
intent.putExtra("usr", usr);
Usr usr = getIntent().getParcelableExtra("usr");
最后,在 ActivityManagerNative 的 startActivity 中执行 Intent 的 writeToParcel 方法。
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
.
.
intent.writeToParcel(data, 0);
.
.
}
这样就完成了对象的传递。
Serializable
其实通过 Java 自带的接口实现序列化后也是可以添加到 intent 当中,进行传输的。不过,虽然实现起来方便,但是性能却比不上 Parcel。但是,我们可以自己重写 writeObject 方法,这样就能提升 Serializable 序列化的性能。具体请点击查看