【问题标题】:android parcelable referencing another parcelable circular dependenceandroid parcelable 引用另一个 parcelable 循环依赖
【发布时间】:2013-08-12 17:10:40
【问题描述】:

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

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

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

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

(对于 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)

【问题讨论】:

    标签: android loops stack-overflow parcelable chain


    【解决方案1】:

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

    AFAIK,打包过程不处理circular object graphs。我刚刚提交了an issue to get this better documented

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

    【讨论】:

    • 如果我必须通过 ContainerClass,这种解决方法会很棒。不幸的是,它是我必须传递给活动的 ItemClass 实例的集合。虽然我可以做相反的事情而不是 p.writeList,因为我在程序的这一部分中并不真正需要这些信息,但当“Parseled”ContainerClass 实例没有_items 时,该实现会导致其他部分出现问题。
    【解决方案2】:

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

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

    【讨论】:

    • 我最终实现了 2 号。
    猜你喜欢
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-08
    • 2012-03-12
    相关资源
    最近更新 更多