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.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)
This will inevitably loop and overflow the stack.
AFAIK, the parceling process does not handle circular object graphs. I just filed an issue to get this better documented.
One workaround is to not do p.writeParcelable( _containerRef );
. Instead, in ContainerClass
, in your ContainerClass(Parcel in)
constructor (or however your CREATOR
is handling it), after reading in your _items
list, iterate over that list and tell each child about its parent.
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 );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With