android parcelable引用另一个parcelable循环依赖

时间:2013-08-11 21:24:26

标签: android loops stack-overflow parcelable chain

真的很简单,但是我在Google上找不到任何相关内容,所以这里有:

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)

2 个答案:

答案 0 :(得分:9)

  

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

AFAIK,parceling进程无法处理circular object graphs。我刚刚提交了an issue to get this better documented

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

答案 1 :(得分: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变通方法,使用静态哈希表,授予每个对象可以由它的parcelable属性唯一标识。 (在我的例子中,我在对象中的数据库中有主键)。

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 );
  }      
}