I am using Parcelable to communicate between fragments. Everything is working good, but sometimes when Android kills app process to free up the memory and user returns to app, the Parcelable gets huge amount of items from arrays like couple millions items instead of 2-3 and of course it throws OOM. I suppose something's wrong with CREATOR, but I can't handle it. The code for parcelable is composed from super class and child class and my interested item class:
base class:
public abstract class BaseRs implements Parcelable {
private String token;
private String msgAlert;
private String simpleMsg;
private AdsObj adsObj;
private Map<String, String> mapSettings;
//getters & setters
public BaseRs() {
}
protected BaseRs(Parcel in) {
token = in.readString();
msgAlert = in.readString();
simpleMsg = in.readString();
adsObj = in.readParcelable(AdsObj.class.getClassLoader());
mapSettings = MapParcelable.readParcelable(in);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(token);
dest.writeString(msgAlert);
dest.writeString(simpleMsg);
dest.writeParcelable(adsObj, flags);
MapParcelable.writeToParcel(dest, mapSettings);
}
}
child class
public class GetSalesItemsRs extends BaseRs {
private SaleCoinItem[] coinPacksArray;
//getters+ setters
protected GetSalesItemsRs(Parcel in) {
super(in);
coinPacksArray = in.createTypedArray(SaleCoinItem.CREATOR);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeTypedArray(coinPacksArray, flags);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<GetSalesItemsRs> CREATOR = new Creator<GetSalesItemsRs>() {
@Override
public GetSalesItemsRs createFromParcel(Parcel in) {
return new GetSalesItemsRs(in);
}
@Override
public GetSalesItemsRs[] newArray(int size) {
return new GetSalesItemsRs[size];
}
};
}
and my interested object
public class SaleCoinItem implements Parcelable {
private int amount;
private double price;
private int sortOrder;
//getters & setters
protected SaleCoinItem(Parcel in) {
amount = in.readInt();
price = in.readDouble();
sortOrder = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(amount);
dest.writeDouble(price);
dest.writeInt(sortOrder);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<SaleCoinItem> CREATOR = new Creator<SaleCoinItem>() {
@Override
public SaleCoinItem createFromParcel(Parcel in) {
return new SaleCoinItem(in);
}
@Override
public SaleCoinItem[] newArray(int size) {
return new SaleCoinItem[size];
}
};
}
The functiona to parcel Map - maybe here is the error ;)
public class MapParcelable {
public static void writeToParcel(Parcel out, Map<String, String> map) {
if (map != null) {
out.writeInt(map.size());
for (Map.Entry<String, String> entry : map.entrySet()) {
out.writeString(entry.getKey());
out.writeString(entry.getValue());
}
}
}
public static Map<String, String> readParcelable(Parcel parcel) {
Map<String, String> map = new HashMap<String, String>();
int size = parcel.readInt();
for (int i = 0; i < size; i++) {
String key = parcel.readString();
String value = parcel.readString();
map.put(key, value);
}
return map;
}
}
I get parcelable obj inside the onCreateView
method :
GetSalesItemsRs mGetSalesItemsRs = getArguments().getParcelable(KEY_PARCEL);
I think the problem is that if the Map is null you're not writing the size field to the Parcel, but when you read it you always read the size field, and it might end up reading some random value. So or you change the code to
if (map != null) {
out.writeInt(map.size());
for (Map.Entry<String, String> entry : map.entrySet()) {
out.writeString(entry.getKey());
out.writeString(entry.getValue());
}
}else{
out.writeInt(0);
}
and you will never get a null value when recreating the class, or you create another boolean field "hasMap" and always write that one