且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

安卓parcelable引用另一个parcelable循环依赖

更新时间:2023-11-22 15:08:40

我一直在琢磨一些,并拿出两个解决方法很有用,如果别人是在同一条船上:

1)(由CommonsWare启发) 把一个标志链上的指示方向的各部分 向上的层次结构是有损耗的,即所有项目的ContainerClass无法恢复。

 类ContainerClass实现Parcelable {
  布尔_parcelableDownHeirarchy = TRUE;
  名单< itemClass时> _items;
  (...)

  私人ContainerClass(包裹中){
    _items = in.readArrayList(ItemClass.class.getClassLoader());
    (...)

    如果(_parcelableDownHierarchy){
      的for(int i = 0; I< _items.size();我++)
        _items.get(我).set_container(本);
    }
  }

  公共无效writeToParcel(包裹磷,INT参数){
    p.writeByte((字节)_parcelableDownHierarchy?1:0);
    如果(_parcelableDownHeirarchy)
      p.writeList(_items);

    (...)
  }
}


类itemClass时实现Parcelable {
  布尔_parcelableDownHeirarchy = TRUE;
  ContainerClass _containerRef;
  (...)

  私人itemClass时(宗地中){
    如果(!_parcelableDownHeirarchy){
      _containerRef = in.readParcelable(ContainerClass.class.getClassLoader());
      //将不包含的项目,在它的_items名单。
    }
  }

  公共无效writeToParcel(包裹磷,INT参数){
    p.writeByte((字节)_parcelableDownHierarchy?1:0);
    如果(!_parcelableDownHeirarchy)//向上的层次结构
      p.writeParcelable(_containerRef);

    (...)
  }
}
 

2)hackish的解决方法,采用静态的哈希表,授予每个对象都可以被唯一确定的是parcelable属性。 (在我来说,我已经在对象在我的数据库中的主键)。

 类ContainerClass实现Parcelable {
  //许可,不得
}


类itemClass时实现Parcelable {
  HaspMap<长,ContainerClass> _parents =新的HashMap<长,ContainerClass>();
  ContainerClass _containerRef;
  (...)

  公共长get_PKhash(){/ *返回唯一标识符* /}

  私人itemClass时(宗地中){
    (...)
    assertTrue((_containerRef = _parents.remove(get_PKhash()))!= NULL);
  }

  公共无效writeToParcel(包裹磷,INT参数){
    (...)//不要写_containerRef
    _parents.put(this.get_PKhash,_containerRef);
  }
}
 

Rather simple scenario really, but I could not find anything related on Google so here goes:

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

This will inevitably loop and overflow the stack.

My question: How am I supposed to deal with a situation where I have to pass an object of the above types through to a new Activity.

(For CommonsWare) Parcelable implementation does indeed not seem to check for, and avoid circular dependencies. Stacktrace with classnames replaced by above names:

08-12 10:17:45.233    5590-5590/com.package E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.***Error
        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)

I've been pondering some more and come up with two workarounds useful if anyone else is in the same boat:

1) (Inspired by CommonsWare) Put a flag on each part of the chain to indicate direction Up the heirarchy is lossy in the sense that all items to the ContainerClass cannot be restored.

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 workaround, employing a static hash table, granted each object can be uniquely identified by it's parcelable attributes. (In my case I have the primary key in my database in the objects).

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