通过 bundle 检索可打包对象是否总是创建新副本?

Does retrieving a parcelable object through bundle always create new copy?

我在创建片段时通过添加到包中将可打包对象传递给片段。在一个实例中,对该分块对象的修改反映了原始对象中的修改,而在另一种情况下则不是。我对这种行为感到有些困惑。 到现在为止,我一直假设通过一个包检索一个 parceled 对象总是创建新对象[不确定它是浅拷贝还是深拷贝]。

有人请澄清 parcelable 行为。

我正在为类似的问题而苦苦挣扎。乍一看,我们似乎总是从 parceled 对象中获得一个新的深拷贝。此外,甚至有 some Whosebug 答案建议使用 Parcelable 接口来克隆对象。所有这些只会增加对该主题的混淆。

这是我经过大量搜索和谷歌搜索后发现的:

  • 仔细看看官方Parceldocumentation。这是重要的引用:

An unusual feature of Parcel is the ability to read and write active objects. For these objects the actual contents of the object is not written, rather a special token referencing the object is written. When reading the object back from the Parcel, you do not get a new instance of the object, but rather a handle that operates on the exact same object that was originally written.

好的,如您所见,在解包过程中有一些特殊对象没有被复制。但这仍然有点令人困惑。这是否意味着我们有另一个对原始对象的强引用而阻止了它的垃圾回收?这些对象的用例是什么?

  • 为了回答上述问题,我决定浏览 Android source code. The methods I was looking for are readStrongBinder and writeStrongBinder which according to the docs do not cause a new object creation when the parcels are sent/received. And I think I found the desired answer in the ResultReceiver.java class。这是有趣的一行:

    mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
    

    要了解这条线的实际作用,我们应该去官方网站AIDL documentation。以下是最重要的部分:

The steps a calling class must take to call a remote interface defined with AIDL:
...
5. In your implementation of onServiceConnected(), you will receive an IBinder instance (called service). Call YourInterfaceName.Stub.asInterface((IBinder)service) to cast the returned parameter to YourInterface type.

A few comments on calling an IPC service:

Objects are reference counted across processes.

所以让我们把所有的东西放在一起:

  1. 无需深拷贝过程即可提取分块对象。
  2. 如果使用 readStrongBinder 方法读取分块对象,则不会创建新实例。我们只是获得了对原始对象的新引用,这个引用可以防止它的释放。
  3. 要知道我们的对象在收到包裹后是否会被深拷贝,我们应该仔细看看具体的Parcelable接口实现。
  4. Android 文档可能真的很混乱,可能需要很多时间才能正确理解它。

希望此信息对您有所帮助。

如果你想阅读一个真实世界的例子,当关于 Parcelable 对象的混淆会导致严重的问题时,请查看我的 blog post.