我在创建Fragment时,通过将Parcelable对象添加到Bundle中来传递它。在某些情况下,对这个Parcelable对象的修改会反映在原始对象中,而在另一些情况下则不会。这种行为让我有点困惑。到目前为止,我一直认为通过Bundle获取Parcelable对象总是会创建新对象[不确定是浅拷贝还是深拷贝]。
请有经验的人解释一下Parcelable的行为。
我在创建Fragment时,通过将Parcelable对象添加到Bundle中来传递它。在某些情况下,对这个Parcelable对象的修改会反映在原始对象中,而在另一些情况下则不会。这种行为让我有点困惑。到目前为止,我一直认为通过Bundle获取Parcelable对象总是会创建新对象[不确定是浅拷贝还是深拷贝]。
请有经验的人解释一下Parcelable的行为。
我曾经遇到过类似的问题。乍一看,我们总是会从打包的对象中获得一个新的深复制。此外,甚至还有一些StackOverflow的答案建议使用Parcelable
接口来克隆对象。这一切只会增加关于这个主题的困惑。
在大量搜索和谷歌之后,我找到了以下内容:
Parcel
文档。这里是重要的引用:Parcel的一个不寻常的特性是读取和写入活动对象。对于这些对象,实际对象的内容没有被写入,而是写入了引用对象的特殊标记。从Parcel读回对象时,您不会得到对象的新实例,而是获得一个操作最初写入的完全相同对象的句柄。
正如您所看到的,有一些特殊的对象在解包期间没有被复制。但这仍然有点让人困惑。这是否意味着我们有了原始对象的另一个强引用,从而防止其垃圾回收?这些对象的用例是什么?
为了回答上述问题,我决定查看Android源代码。我寻找的方法是readStrongBinder
和writeStrongBinder
,根据文档,它们在发送/接收包时不会导致新对象创建。我认为我在ResultReceiver.java类中找到了想要的答案。这里是一个有趣的行:
mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
为了理解这行代码实际在做什么,我们需要查看官方的AIDL文档。以下是其中最重要的部分:readStrongBinder
方法读取封送的对象,则不会创建新的实例。我们只是获得对原始对象的新引用,并且该引用可以防止其被释放。
3. 要知道在接收到封包后我们的对象是否会被深度复制,我们应该更详细地研究具体的Parcelable
接口实现。
4. Android文档可能真的很令人困惑,理解正确可能需要花费很多时间。Parcelable
对象的混淆可能会导致严重问题,请查看我的博客文章。