返回

意图(Intent.FLAG_ACTIVITY_CLEAR_TOP)真的是 clear top 吗?

Android

在许多情况下,开发人员需要在新的 Activity 界面中显示一些来自于上一个 Activity 界面中的数据,这需要两个 Activity 间进行通信。为了避免这些数据在 Activity 跳转时丢失,开发者们往往会将这些数据存储在某个全局变量中,比如单例对象或其他全局变量,但是这样做会造成不必要的麻烦。

我们建议使用 Intent 携带数据在 Activity 间传递,Intent 中提供了诸如 putExtra(String key, Parcelable value) 的方法,支持传递任意 Parcelable 对象。但是开发者们常常混淆了两个参数 keyvalue ,很多开发者在使用 Intent 携带数据传递时,传递过去的数据类型并不属于 Parcelable,而是基本数据类型或 String。

可能不少读者感到疑惑,为什么我会在 Flag 与 Intent 间进行对比,这是因为 Intent 携带数据过程实际上就是在往 Activity 的 Intent 实例中添加数据,我们总所周知的 Flag 正是通过 Bundle 与 Intent 相关联,Intent 的 putExtra 方法会通过 Parcelable 的 write 方法将数据写入到 Bundle 的数据项中。

实际上,在早期的 Android 系统中,传递 String 与基本数据类型是完全没问题的,那时 Intent 的内部数据是直接通过 Bundle 存储的,而 Bundle 支持存储 String 与基本数据类型。

当 Android 系统进入 4.0 后,Intent 内部的数据存储形式发生了改变,Intent.putExtra 不再通过 Bundle 的 put 方法写入数据,而是通过自己的 put 方法,开发者们使用 Intent 的 putExtra 方法写入非 Parcelable 对象时,Intent 会将数据包装成一个 Bundle,然后再通过 Bundle 的 put 方法写入。然而这个中间过程会出问题,因为不是 Parcelable 的对象无法被写入 Bundle,所以 Intent 在写入时就会失败,自然也无法成功地通过 Intent 将数据传递给下一个 Activity,而我们在接收时会拿到一个空数据或空指针。

知道了问题的根源,我们的解决方案也就迎刃而解了,只需要将传递给下一个 Activity 的数据进行 Parcelable 的包装即可,可以使用 new ParcelableWrapper(value) 包装成一个实现了 Parcelable 接口的类,然后再通过 putExtra 方法传递给下一个 Activity。

收到数据后,可通过下列方法取出:

Object value = ((ParcelableWrapper) intent.getParcelableExtra("key")).getValue();

当然了,除了使用这种方式包装数据,我们也可以自己实现 Parcelable 接口,从而将任意自定义数据转换为 Parcelable 对象,这个操作相对繁琐,并且需要根据实际业务逻辑进行自定义,这里就不再详细介绍了。