Search code examples
androidandroid-intentandroid-activityparcelable

Pass parcelable object containing Map between Activity


My class ExpenseFB, which implements Parcelable, contains a Map of UserFB (which implements Parcelable too):

ExpenseFB:

public class ExpenseFB implements Parcelable {

private String id;
private String name;
private String description;
private String whopaidID;
private String whopaidName;
private Double amount;
private Map<String, UserFB> partecipants;
// setters and getters...
@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(id);
    dest.writeString(name);
    dest.writeString(description);
    dest.writeString(whopaidID);
    dest.writeString(whopaidName);
    dest.writeMap(partecipants);
}


protected ExpenseFB(Parcel in) {
    id = in.readString();
    name = in.readString();
    description = in.readString();
    whopaidID = in.readString();
    whopaidName = in.readString();
    in.readMap(partecipants,UserFB.class.getClassLoader());
}

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

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

UserFB:

public class UserFB implements Parcelable{

private String id;
private String name;
private String email;
private Map<String, GroupFB> groups;
private Map<String, UserFB> friends;
// setters and getters
@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(id);
    dest.writeString(name);
    dest.writeString(email);
    dest.writeMap(groups);
    dest.writeMap(friends);
}

protected UserFB(Parcel in) {
    id = in.readString();
    name = in.readString();
    email = in.readString();
    in.readMap(groups,GroupFB.class.getClassLoader());
    in.readMap(friends,UserFB.class.getClassLoader());
}

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

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

I want to pass an ExpenseFB object between two Activities by adding the object ExpenseFB to the intent:

intent.putExtra("id", expenseFB);

When, in debug mode, I execute getIntent().getParcelableExtra("id") in the second activity it raises the following exception when tries to do the readMap() method on the partecipants map:

 ... Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.Map.put(java.lang.Object, java.lang.Object)' on a null object reference

I see that the partecipants map in the first activity is filled: I think that the problem is in the writeMap() method.
Does exist a standard or better way to pass a Parcelable object containing a Map?
Have I to call another method to parcel the Map?

I don't want to use Serializable object because I read that they make worse performances.


Solution

  • The problem is that readMap() is used to read data from a Parcel into and existing Map. You haven't created the Map before calling readMap(), so you get the NullPointerException.

    You can solve this by initializing the map when you declare it:

    private Map<String, GroupFB> groups = new HashMap<String, GroupFB>();
    private Map<String, UserFB> friends = new HashMap<String, UserFB>();
    

    Or, you can create the empty Map in the UserFB constructor, like this:

    protected UserFB(Parcel in) {
        id = in.readString();
        name = in.readString();
        email = in.readString();
        groups = new HashMap<String, GroupFB>();
        in.readMap(groups,GroupFB.class.getClassLoader());
        friends = new HashMap<String, UserFB>()
        in.readMap(friends,UserFB.class.getClassLoader());
    }