文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android Intent传递数据底层分析详细介绍

2022-06-06 11:51

关注

Android  Intent传递数据底层分析详细介绍

我们知道在Activity切换时,如果需要向下一个ActivityB传递数据,可以借助Intent对象的putExtra方法。

但是不知各位有没有想过这样一个问题:ActivityB中获取到的对象跟上一个Activity中的那个对象有什么关系?

换句话说就是,我在ActivityB中通过Intent获取的对象跟ActivityA中的那个对象,有没有可能是同一个对象?

按照常理来说,博主提出一个设想后续的就是证明过程了,但是我要遗憾的告诉你,这里并非是同一个对象。(PS:废话,如果是同一个对象,那还有EventBus这些东西什么事儿 T_T)

那么问题又来了,这两个Activity都在同一个进程里面,甚至都在同一个线程里面,数据本来就是可以共享的,为什么从一个Activity传到另一个Activity之后,就不是一个对象了呢?它从什么时候变成另外的对象的呢?

不着急,且听我慢慢道来。

Intent是什么东西?


public class Intent implements Parcelable, Cloneable

上面是Intent类的完整声明,可以知道它实现了Parcelable接口。Parcelable接口是什么呢?这东西是Android上专门用来对数据进行序列化的,并且在跨进程通讯时Parceable对象是可以直接传输的。

接下来我们来看看将数据放入Intent的时,做了哪些处理。

以String为例,先看putExtra方法的代码


public Intent putExtra(String name, String value) {
    if (mExtras == null) {
      mExtras = new Bundle();
    }
    mExtras.putString(name, value);
    return this;
  }

很简单,就是将数据放入mExtras这个Bundle对象中,顺便说一句Bundle类也实现了Parcelable接口。继续往下跟代码


public void putString(@Nullable String key, @Nullable String value) {
    unparcel();
    mMap.put(key, value);
  }

内部就是将数据放入一个Map中保存。到这里数据放入Intent的过程就完成了,实际上就是Intent中有一个Bundle对象,而这个Bundle对象中又有一个Map,然后数据就保存在这里。至于那个unparcel()方法与我们的分析过程无关,有兴趣的读者可以去研究一下。

然后,我们再看取数据的过程。

继续以String作为例子,看Intent中的代码


public String getStringExtra(String name) {
    return mExtras == null ? null : mExtras.getString(name);
  }

mExtras应该很熟悉了,这是个Bundle对象,刚刚保存数据的时候就是把数据保存在它里面的。再看它的getString方法


public String getString(@Nullable String key) {
    unparcel();
    final Object o = mMap.get(key);
    try {
      return (String) o;
    } catch (ClassCastException e) {
      typeWarning(key, o, "String", e);
      return null;
    }
  }

就是直接从Map里面拿出我们之前保存的String,try语句只是在验证取出的数据是否为String类型。
那照这么分析的话,两个Activity中的对象应该就是同一个对象才对啊!!为什么又说不是同一个对象呢?

为什么不是同一个对象?

如果你在putExtra之后,马上又getExtra出来,那么你取出来的对象肯定是同一个对象,这个没错!
但是这里我们要注意两点:

1.Intent中允许保存的数据类型是有限制的,准确的说是Bundle的限制,因为实质上数据是保存在Bundle中。如果我们要保存自己定义的对象,那么我们的对象必须实现了Parcelable接口或者Serializable接口。

2.我们使用Intent的方式,基本都是在一个Activity中存入,然后从另一个Activity中取出。

那么问题很明显就出在Activity的启动过程了。详细的启动过程大家可以参考老罗的文章Activity启动过程。

这里大概说一下,首先我们的app运行在app自己的进程appProcess中,然后系统在启动的时候会启动一个系统进程systemProcess。而在Activity启动时,需要向一个叫做ActivityManagerService的系统服务去注册,这样我们的Activity才能有生命周期的回调。这个ActivityManagerService服务就运行在systemProcess中。注册完之后,再回到appProcess中,完成新Activity的启动。在这个注册过程中,我们的intent是全程参与的。

说到这里就明白了,当我们调用startActivity(intent)启动另外的Activity的时候,我们的intent已经完成了两次跨进程通信,而它里面的对象已经经历了两轮序列化和反序列化,肯定不可能是同一个对象了。

这里顺便说一个问题:为什么Serializable也可以跨进程传输?

熟悉AIDL的同学都很清楚,AIDL跨进程通信支持的数据类型是:

Java 的原生类型,如int,boolean,long,float… String 和CharSequence List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型 AIDL 自动生成的接口 需要导入(import) 实现android.os.Parcelable 接口的类. 需要导入(import)。

这里并不包括Serializable类型。

于是去看了源码,发现是Parcel自己对Serializable类型的对象做了兼容,可以直接写入其中。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

您可能感兴趣的文章:Android 通过Intent使用Bundle传递对象详细介绍Android开发中Intent用法总结Android常用的intent action汇总Android中Intent传递对象的3种方式详解Android实现打开各种文件的intent方法小结Android Activity与Intent详解及示例代码Android使用Intent发送短信的实现方法Android Activity中使用Intent实现页面跳转与参数传递的方法Android利用Intent实现记事本功能(NotePad)


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯