8

相当简单的场景,但我在谷歌上找不到任何相关的东西,所以这里是:

class ContainerClass implements Parcelable {
  List<ItemClass> _items;
  (...)

  public void writeToParcel( Parcel p, int args ) {
    p.writeList( _items );
    (...)
  }
}

class ItemClass implements Parcelable {
  ContainerClass _containerRef;      
  (...)

  public void writeToParcel( Parcel p, int args ) {
    p.writeParcelable( _containerRef );
    (...)
  }      
}

这将不可避免地循环和溢出堆栈。

我的问题:我应该如何处理必须将上述类型的对象传递给新活动的情况。

(对于 CommonsWare)Parcelable 实现似乎确实没有检查并避免循环依赖。将类名替换为上述名称的 Stacktrace:

08-12 10:17:45.233    5590-5590/com.package E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.StackOverflowError
        at com.package.ContainerClass.writeToParcel(ContainerClass.java:139)
        at android.os.Parcel.writeParcelable(Parcel.java:1254)
        at com.package.ItemClass.writeToParcel(ItemClass.java:182)
        at android.os.Parcel.writeParcelable(Parcel.java:1254)
        at android.os.Parcel.writeValue(Parcel.java:1173)
        at android.os.Parcel.writeList(Parcel.java:622)
        at com.package.ContainerClass.writeToParcel(ContainerClass.java:144)
        at android.os.Parcel.writeParcelable(Parcel.java:1254)
        at com.package.ItemClass.writeToParcel(ItemClass.java:182)
        at android.os.Parcel.writeParcelable(Parcel.java:1254)
        at android.os.Parcel.writeValue(Parcel.java:1173)
        at android.os.Parcel.writeList(Parcel.java:622)
4

2 回答 2

9

这将不可避免地循环和溢出堆栈。

AFAIK,打包过程不处理圆形对象图。我刚刚提交了一个问题,以便更好地记录这一点

一种解决方法是不这样做p.writeParcelable( _containerRef );。相反,ContainerClass在你的ContainerClass(Parcel in)构造函数中(或者你CREATOR正在处理它),在你的_items列表中读取之后,迭代该列表并告诉每个孩子它的父母。

于 2013-08-11T22:26:24.763 回答
1

我一直在思考更多,并提出了两个有用的解决方法,如果其他人在同一条船上:

1)(受 CommonsWare 启发)在链的每个部分放置一个标志以指示方向向上的层次结构是有损的,因为 ContainerClass 的所有项目都无法恢复。

class ContainerClass implements Parcelable {
  boolean _parcelableDownHeirarchy = true;
  List<ItemClass> _items;
  (...)

  private ContainerClass( Parcel in ) {
    _items = in.readArrayList( ItemClass.class.getClassLoader() );
    (...)

    if ( _parcelableDownHierarchy ) {
      for ( int i = 0; i < _items.size(); i++ ) 
        _items.get( i ).set_container( this );
    }          
  }

  public void writeToParcel( Parcel p, int args ) {
    p.writeByte( (byte)_parcelableDownHierarchy ? 1 : 0 );
    if ( _parcelableDownHeirarchy )
      p.writeList( _items );

    (...)
  }
}


class ItemClass implements Parcelable {
  boolean _parcelableDownHeirarchy = true;
  ContainerClass _containerRef;      
  (...)

  private ItemClass( Parcel in ) {
    if ( !_parcelableDownHeirarchy ) {
      _containerRef = in.readParcelable( ContainerClass.class.getClassLoader() );
      //Won't contain item in it's _items list.          
    }
  }

  public void writeToParcel( Parcel p, int args ) {
    p.writeByte( (byte)_parcelableDownHierarchy ? 1 : 0 );
    if ( !_parcelableDownHeirarchy ) //Up the heirarchy
      p.writeParcelable( _containerRef );

    (...)
  }      
}

2)Hackish 解决方法,采用静态哈希表,授予每个对象可以通过其可打包属性唯一标识。(在我的情况下,我的数据库中有对象的主键)。

class ContainerClass implements Parcelable {
  //Leave be
}


class ItemClass implements Parcelable {
  HaspMap<Long, ContainerClass> _parents = new HashMap<Long, ContainerClass>();
  ContainerClass _containerRef;      
  (...)

  public long get_PKhash() { /* Return unique identifier */ }

  private ItemClass( Parcel in ) {
    (...)
    assertTrue( (_containerRef = _parents.remove( get_PKhash() )) != null );
  }

  public void writeToParcel( Parcel p, int args ) {
    (...)//Don't write _containerRef
    _parents.put( this.get_PKhash, _containerRef );
  }      
}
于 2013-08-12T09:10:40.510 回答