Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parcelable works without correct implementation

In a Android App I'm sending a Bundle from an Activity to a Fragment.

public class Bar implements Parcelable {

private Map<String, String> hash;
private int id;

protected Bar(Parcel in) {
    id = in.readInt();
}

public Bar(int id, Map<String,String> map){
    this.hash=map;
    this.id=id;
}

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

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

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

@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeInt(id);
}
}

I've used Android Studios Implement Parcelable inteli sense help and auto generated the above code and it has no implementation for the Map.

When I send this to my Fragment like this:

 Map<String,String> map = new HashMap<String, String>();
    map.put("foo","bar");
    map.put("foobar","barfoo");
    Bar foo = new Bar(1,map);

    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle();
    fragment.setArguments(bundle);
    bundle.putParcelable("foo",foo);
    FragmentTransaction fragmentTransaction =  
    getSupportFragmentManager().beginTransaction();
    fragmentTransaction.add(R.id.container, fragment, "foo");
    fragmentTransaction.commit();

And somehow the Map appears to contain the content when it appears in the fragment. Why is this? The behaviour I would excpect is that Id is transfered and Map is skipped. This is possible to repeat by just creating an Activity, a fragment and my Bar and send it as a Bundle. I've tried searching for an answer but I'm not quite sure on how to formulate the question.

Is it a bug or a feature that is supposed to work this way?

like image 619
Andreas Andersson Avatar asked Aug 23 '17 06:08

Andreas Andersson


1 Answers

Parceling is done lazily, which means your Bar instance is not being parceled when you pass it to the Fragment. I.e. writeToParcel is not called.

Parceling is quite expensive (in terms of resources), so it's better to avoid it if possible. If the Bundle is not sent to another process there is no need to parcel it. Usually parceling is done when IPC is involved. So even during a configuration change there is no need to parcel the Bundle. If, however, your process is killed when the activity is in the background, the arguments Bundle would be parceled because it's stored in another process. This is also true when you send it in an Intent.

So in your case the Map would go lost when the instance is actually parceled. It's only still present because it's not really parceled and the Fragment receives the exact same instance of Bar.

like image 199
Marten Avatar answered Nov 15 '22 04:11

Marten