Parcelable如何运作?

时间:2016-01-15 17:51:38

标签: java android fragment parcelable screen-rotation

我想在屏幕旋转期间保留复杂的java对象,所以我使对象Parcelable并实现了必要的方法:

  1. 在writeToParcel(Parcel dest,int flags)方法中,我将一些保存的值保存到" dest"。
  2. 在Parcelable.Creator的createFromParcel(Parcel源)方法中,我从" source"中获取了值。按正确的顺序并返回适当的对象。
  3. 然后在Fragment的onSaveInstanceState中我保存了Parcelable:

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("myObject", myObject);
    }
    

    并将我的对象放入Fragment' onCreate:

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      MyObject myObject = savedInstanceState.getParcelable("myObject");
    }
    

    这完美无缺。

    然后我做了一个测试:

    1. 删除了writeToParcel方法中的所有代码。
    2. 在createFramParcel方法中返回null。
    3. 当我运行应用程序时,我得到了完全相同的结果!我得到了一个包含所有适当值的对象。

      为什么会这样? Parcelable是否可以创建" Parcelable对象"自动?

1 个答案:

答案 0 :(得分:7)

是的,所以这与Bundle在内部处理缓存和分区的方式有关。当您致电putParcelable()时,它会运行以下代码:

public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
    unparcel();
    mMap.put(key, value);
    mFdsKnown = false;
}

基本上,Bundle中的数据不会立即写入Parcel - mMapArrayMap<String, Object>,它包含所有对象的缓存Bundle,因为他们已插入或删除。

在某些时候,writeToParcel()会调用Bundle,此时mMap中的所有内容都会被写入mParcelledData

所以基本上,当你进行配置更改时,Bundle仍然没有被写入Parcel,所以你传入的对象的同一个实例仍然存储在Bundle mMap(因此您的对象也从未调用writeToParcel() - 您可以通过断言配置更改前后的对象具有相同的{{}来确认这一点1}})。

您可以在System.identityHashCode()

中查看有关此内容的说明
BaseBundle

因此,如果您要将// Invariant - exactly one of mMap / mParcelledData will be null // (except inside a call to unparcel) ArrayMap<String, Object> mMap = null; /* * If mParcelledData is non-null, then mMap will be null and the * data are stored as a Parcel containing a Bundle. When the data * are unparcelled, mParcelledData willbe set to null. */ Parcel mParcelledData = null; 对象写入保存状态包,并将应用程序置于后台,直到进程终止(或者我相信您可以通过运行Parcelable强制执行此操作)然后恢复,然后您将遇到数据未正确分配的问题。