Issues with List of Parcelables
lance0428 opened this issue · 5 comments
I am having issues with List support. I keep getting NullPointers when I try to read my object. Below is the objects involed:
Root object I am trying to parcel
public class MyObjectToStore implements Parcelable {
public List<ObjectInList> objectsInList;
public String myObjectValue;
public MyObjectToStore() {
}
private MyObjectToStore(Parcel in) {
in.readTypedList(objectsInList, ObjectInList.CREATOR);
this.myObjectValue = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(objectsInList);
dest.writeString(this.myObjectValue);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<MyObjectToStore> CREATOR = new Creator<MyObjectToStore>() {
public MyObjectToStore createFromParcel(Parcel source) {
return new MyObjectToStore(source);
}
public MyObjectToStore[] newArray(int size) {
return new MyObjectToStore[size];
}
};
}
Inner Parcelable in list
public class ObjectInList implements Parcelable {
String objectInListValue;
private ObjectInList(Parcel in) {
this.objectInListValue = in.readString();
}
public ObjectInList(String objectInListValue) {
this.objectInListValue = objectInListValue;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.objectInListValue);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ObjectInList> CREATOR = new Creator<ObjectInList>() {
public ObjectInList createFromParcel(Parcel source) {
return new ObjectInList(source);
}
public ObjectInList[] newArray(int size) {
return new ObjectInList[size];
}
};
}
Test that shows Exception
public class MyObjectToStoreTest extends TestCase {
public void testParcelable() {
MyObjectToStore objectToStore = new MyObjectToStore();
objectToStore.myObjectValue = "MyObjectValue";
List<ObjectInList> list = new ArrayList<ObjectInList>();
list.add(new ObjectInList("Object1"));
list.add(new ObjectInList("Object2"));
objectToStore.objectsInList = list;
Parcel parcel = Parcel.obtain();
objectToStore.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
MyObjectToStore fromParcel = MyObjectToStore.CREATOR.createFromParcel(parcel);
assertEquals("MyObjectValue", fromParcel.myObjectValue);
assertEquals(2, fromParcel.objectsInList.size());
assertEquals("Object1", fromParcel.objectsInList.get(0).objectInListValue);
assertEquals("Object2", fromParcel.objectsInList.get(1).objectInListValue);
}
}
Exception
java.lang.NullPointerException
at android.os.Parcel.readTypedList(Parcel.java:1797)
at objects.MyObjectToStore.<init>(MyObjectToStore.java:27)
at objects.MyObjectToStore.<init>(MyObjectToStore.java:8)
at objects.MyObjectToStore$1.createFromParcel(MyObjectToStore.java:33)
at objects.MyObjectToStore$1.createFromParcel(MyObjectToStore.java:31)
at objects.MyObjectToStoreTest.testParcelable(MyObjectToStoreTest.java:24)
It seems to blow up because the list in MyObjectToStore is not being initialized properly by the generated code in private MyObjectToStore(Parcel in). Shouldn't that constructor generate something like
private MyObjectToStore(Parcel in) {
objectsInList = new ArrayList<ObjectInList>(); // new
in.readTypedList(objectsInList, ObjectInList.CREATOR);
this.myObjectValue = in.readString();
}
Am I missing something? Is this an unimplemented feature, a bug, or a compromise because the code generator doesn't know what Type of list it is?
Yes, you are right. Consutructor should look like you suggested but the type of List is now known.
I would name this behaviour as something between compromise and a bug. I don't have idea how to solve this problem, but for sure generator should not generate code that compiles and throws runtime exception.
Do you have any idea how to solve this? Do you think that assuming that list should be ArrayList by developer would be the way to go?
Implementation I can think of would instantiate concrete list if type is known. Otherwise it would fallback to default - ArrayList. I think such solution should be good enough. Any suggestions?
I agree it's best to use the concrete list type if known (derived either from the field type if != List
, or from the initialized value). Otherwise, defer to ArrayList
if unspecified.
Right now it should be creating an ArrayList
though in the latest, as far as I know.
I would suggest to use createTypedArrayList
:
objectsInList = in.createTypedArrayList(ObjectInList.CREATOR)
Agree 100%
This should be fixed in 0.6.2 (in review by JetBrains).