Emil Adz Emil Adz - 5 months ago 10
Android Question

How to create a two dimensional parcelable array of parcelables:

I have to following parcelable object:

public class CGameCard implements Parcelable {
...

private int mX;
private int mY;
private String mObjectName;
private int mState;

public CGameCard(int aX, int aY, String aObjectName) {
mX = aX;
mY = aY;
mObjectName = aObjectName;
mState = CARD_STATE_NOT_MATCHED;
}

public int getX() {
return mX;
}

public int getY() {
return mY;
}

public String getObjectName(){
return mObjectName;
}

public int getState() {
return mState;
}

...

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.mX);
dest.writeInt(this.mY);
dest.writeString(this.mObjectName);
dest.writeInt(this.mState);
}

protected CGameCard(Parcel in) {
this.mX = in.readInt();
this.mY = in.readInt();
this.mObjectName = in.readString();
this.mState = in.readInt();
}

public static final Creator<CGameCard> CREATOR = new Creator<CGameCard>() {
@Override
public CGameCard createFromParcel(Parcel source) {
return new CGameCard(source);
}

@Override
public CGameCard[] newArray(int size) {
return new CGameCard[size];
}
};
}


I want to create a two dimensional parcelable array of those objects in order to store it in the shared preferences for configuration changes.
this is what being generated by the parcelable android studio plugin:

public class GameCardArrArr implements Parcelable {
private CGameCard[][] mArray;

public GameCardArrArr(CGameCard[][] array) {
mArray = array;
}

public CGameCard[][] getArray() {
return mArray;
}

public void setArray(CGameCard[][] mArray) {
this.mArray = mArray;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(this.mArray, flags);
}

protected GameCardArrArr(Parcel in) {
this.mArray = in.readParcelable(CGameCard[][].class.getClassLoader());
}

public static final Creator<GameCardArrArr> CREATOR = new Creator<GameCardArrArr>() {
@Override
public GameCardArrArr createFromParcel(Parcel source) {
return new GameCardArrArr(source);
}

@Override
public GameCardArrArr[] newArray(int size) {
return new GameCardArrArr[size];
}
};
}


Which is not accepted by the compiler because obviously it not correct.

The Question: What would be the correct right way to create this parcelable?

thanks in advance.

Answer

First, I will warn that there is a very strict size limit of 1 MB when transferring parcelables around. If you do a double array like this, then I can imagine it will be very easy to hit that limit and cause a crash.

Anyway, to answer the question. You can put absolutely anything you want in a Parcel object that is needed to recreate the object. So in this case, you need to know the two dimensions of the array, and then just fill the array based on those dimensions. All that you have to do is ensure that the way you write them is exactly the same way you read them (which is the case for all parcelables).

One method would be to first write how many arrays are in your double array, then write each array.

So in this case your writeToParcel will be something like this:

void writeToParcel(Parcel dest, int flags) {
   int numOfArrays = mArray.length;
   dest.writeInt(numOfArrays); // save number of arrays
   for (int i = 0; i < numOfArrays; i++) {
      dest.writeParcelableArray(mArray[i], flags);
   }
}

So now you know the very first int is the number of Card arrays in your double array.

GameCardArrArr(Parcel in) {
   int numberOfArrays = in.readInt();
   mArray = new CGameCard[numberOfArays][];
   for (int i = 0; i < numberOfArrays; i++) {
      mArray[i] = (CGameCard[]) in.readParcelabeArray(CGameCard.class.getClassLoader());
   }
}