最近一位采访者问我一个非常棘手的问题。 问题有几个部分。
我给的答案 -
Parcelable为开发人员提供了限制对象的能力 在某种程度上使用它的速度更快。
我对这部分感到困惑,所以决定使用serializable和parcelable之间的区别:p(聪明的huuuhhh!), http://www.developerphil.com/parcelable-vs-serializable/使用了此引用。
我给的答案 -
因为String / int是原始数据类型,如果我们使用了 直接包装类,可能我们不得不使用parcelable(我 我不确定那部分)
谷歌搜索后我没有得到任何有用的链接,我或者面试官对答案也不太满意。 如果你们能提供帮助,那就太好了!
答案 0 :(得分:6)
为什么(问题是为什么而不是如何)在从一个活动发送到另一个活动而不是直接发送时需要包裹对象
Parcelling / serializing对象并不像你猜到的那样速度。
当您在活动之间,特别是在不同的应用程序之间发送数据时(请记住,Intent
对象不仅适用于您自己的活动之间的通信,也适用于您和其他应用之间的通信。好吧),您不能指望发送方和接收方可以访问相同的内存地址空间。
Android的文档指出应用程序在自己的离散内存空间中运行。以下是来自文档的引用:
每个进程都有自己的虚拟机(VM),因此应用程序的代码与其他应用程序隔离运行。
因此,当您想要将对象myObject
发送给某些接收Activity
时,您无法发送其引用/指针,因为接收方无法访问指针指定的位置。相反,您必须发送一些接收者可以访问和使用的myObject
代表 - 这就是为什么您需要将编组数据转换为可以解组的形式,最简单的方法是简单地使用对象实现Serializable
的类,它允许Java尽最大努力将对象转换为可以轻松发送和解组的字节数组。由接收者。但由于Serializable
使用反射,因此速度很慢。
您可以使用其他更快速编组数据的方法 - 例如,使用像JSON
这样的库将对象转换为Gson
表示形式,然后将其发送到任何方式JSON
文档可以表示为String
,并可以轻松转换回Java Object
。另一种方法,在所有情况下可能更快,使用Parcelable
接口,您可以指定完全您希望如何编组数据,完全如何它应该是未编组的。它基本上可以让您更好地控制对象的传输。
tl:dr :使用Parcelling / Serializing等因为你不能发送内存地址,所以你必须发送对象的实际数据,它必须在某些地方表示形成。
在使用Bundle时,当我们使用String时,int我们不需要包裹数据,所以你认为String / int默认是在内部分配的吗?
Bundle
内部的工作原理是它将所有内容放入Map
并根据需要包裹/取消数据集(即调用get / put时)。要将对象放入Bundle
,对象的类需要实现Serializable
或Parcelable
,因为它需要告诉Bundle
它应该如何在内部编组/解组。
但原始类型和字符串非常简单并经常使用,以至于开发人员不需要指定 需要发生的事情,Bundle
提供方便的方法。我无法在最低级别的工作中给出一个可靠的答案,因为很多Parcel
代码是本地实现的,我无法在线找到它,但它们必须直接转换为它们的以字节为单位的表示。
答案 1 :(得分:0)
只是要添加@ uj-所说的,需要Parcelling / Serializing,因为@ uj-表示它将通过JVM发送,因此需要将它们转换为某种格式,以便对方能够理解。
让我举一个例子来解释为什么需要序列化/分配,
您正在将用“C ++”编写的应用程序中的数据发送到用java编写的应用程序,因此以下是类,
在C ++中,
class Android {
public: int dataToSend; //for example purpose making field public and omitting setter/getters
}
在Java中,
class Android{
public int dataToSend;
}
假设C ++代码生成动态库(将通过使用标准C ++编译器进行编译然后链接生成),Java代码生成jar(通过使用javac进行编译)。
当C ++应用程序将数据(Android类的对象)发送到java应用程序时,它在C ++中编译和链接的方式与它在java中编译的方式完全不同,因此java会想知道这个C ++是什么申请已发送给我。
因此,为了摆脱这些问题,需要序列化/分配,这将确保两个应用程序都知道数据在通过网络传输时如何转换(在android的情况下如何将其传输到另一个活动,可能在相同或不同的应用)。
当我们开始比较Serialization和Parcelling时,Parcelling占了上风,因为我们将在发送数据时指定数据必须转换的方式,否则在序列化的情况下,使用反射将对象转换为字符串反思总是需要时间。因此,与序列化相比,Parcelling更快。
关于第二个问题,
如果我们考虑上面的例子,那么我们可以说String和int是原始类型(其中没有用户定义的字段),因此android将能够处理将要发送的数据的编组和解组。 / p>
当我们继续深入挖掘时,我尝试了解代码,最终得到了@uj所说的本机代码。
一些来自android源代码的摘录: 在写包裹时:
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
parcel.writeArrayMapInternal(mMap);
int endPos = parcel.dataPosition();
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
在阅读包裹时,
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
int offset = parcel.dataPosition();
parcel.setDataPosition(offset + length);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
p.setDataPosition(0);
mParcelledData = p;
设置在写入时识别包裹起点的幻数,并在读取包裹时使用相同的数字。
希望我回答你的问题。