Android parcelable referenciando otra dependencia circular parcelable

En realidad escenario bastante simple, pero no pude encontrar nada relacionado con Google por lo que aquí va:

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

Esto inevitablemente hará un bucle y desbordará la pila.

Mi pregunta: ¿Cómo se supone que debo hacer frente a una situación en la que debo pasar un objeto de los tipos anteriores a una nueva Actividad.

(Para CommonsWare) Implementación parcelable en realidad no parece buscar y evitar dependencias circulares. Stacktrace con nombres de clase reemplazados por nombres anteriores:

 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) 

Esto inevitablemente hará un bucle y desbordará la pila.

AFAIK, el proceso de parcelado no maneja gráficos de objetos circulares . Acabo de presentar un problema para obtener esto mejor documentado .

Una solución es no hacer p.writeParcelable( _containerRef ); . En su lugar, en ContainerClass , en su constructor ContainerClass(Parcel in) (o, sin embargo, su CREATOR está manejando), después de leer en su lista _items , iterar sobre esa lista y decirle a cada niño sobre su padre.

He estado reflexionando un poco más y llegar a dos soluciones útiles si alguien está en el mismo barco:

1) (Inspirado por CommonsWare) Ponga una bandera en cada parte de la cadena para indicar la dirección Encima de la herencia es lossy en el sentido que todos los artículos a la clase de contenedor no pueden ser restaurados.

 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 solución, el empleo de una tabla hash estática, concedido a cada objeto puede ser identificado de forma única por sus atributos parcelables. (En mi caso tengo la clave principal en mi base de datos en los objetos).

 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 ); } } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.