【问题标题】:Does retrieving a parcelable object through bundle always create new copy?通过捆绑检索可打包对象是否总是创建新副本?
【发布时间】:2016-10-07 11:23:15
【问题描述】:

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

请有人澄清可打包的行为。

【问题讨论】:

    标签: android android-fragments parcelable android-bundle


    【解决方案1】:

    我正在努力解决类似的问题。乍一看,我们似乎总是从打包的对象中获得一个新的深拷贝。此外,甚至还有some StackOverflow 的答案建议使用Parcelable 接口来克隆对象。所有这些只会增加对该主题的混淆。

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

    Parcel 的一个不同寻常的功能是能够主动读写 对象。对于这些对象,对象的实际内容不是 写入,而是写入引用对象的特殊标记。 从包裹中读取对象时,您不会得到新的 对象的实例,而是在 与最初编写的对象完全相同。

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

    • 为了回答上述问题,我决定查看 Android source code。我正在寻找的方法是readStrongBinderwriteStrongBinder,根据文档,它们在发送/接收包裹时不会导致新的对象创建。我想我在ResultReceiver.java 类中找到了想要的答案。这是有趣的一行:

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

      要了解这条线实际上在做什么,我们应该去官方AIDL documentation。以下是最重要的部分:

    调用类必须采取的步骤来调用定义的远程接口 与 AIDL:
    ...
    5. 在你的 onServiceConnected() 实现中,你会收到一个 IBinder 实例(称为服务)。称呼 YourInterfaceName.Stub.asInterface((IBinder)service) 来转换 将参数返回到 YourInterface 类型。

    关于调用 IPC 服务的几个 cmets:

    对象被引用计数跨进程。

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

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

    希望这些信息对您有所帮助。

    如果您想了解一个真实的示例,当关于 Parcelable 对象的混淆会导致严重问题时,请查看我的 blog post

    【讨论】:

    • 这是我目前的测试。如果我们通过 Intent+Parcelable 将一个对象传递给 Activity,它是按值传递的。如果我们通过 Parcelable 将一个对象传递给 Fragment,它是通过引用传递的。但是,我认为这种行为并不能保证,因为它没有被记录在案。
    猜你喜欢
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多