欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-14 15:10:52
android  intent传递数据底层分析详细介绍 我们知道在activity切换时,如果需要向下一个activityb传递数据,可以借助intent对象的...

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类型的对象做了兼容,可以直接写入其中。

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

上一篇:

下一篇: