Search code examples
javaandroidandroid-intentparcelable

Parcleable extra not there after starting activity


I am trying to implement Parcleable so that I can add it as an extra (this is a requirement).

Here is a slimmed down version of the class SwinImage which only shows relevant details, namely the parts which are derived from Parcleable:

package com.example.kevin.imagemetadata;
import android.os.Parcel;
import android.os.Parcelable;

public class SwinImage implements Parcelable
{
    public SwinImage(String imageName, String location, String[] keywords, String imageDate, boolean share, String email, int rating)
    {
        update(imageName, location, keywords, imageDate, share, email, rating);
    }

    //A constructor for when we havent assigned any metadata.
    public SwinImage(String imageName)
    {
    }

    public void update(String imageName, String location, String[] keywords, String imageDate, boolean share, String email, int rating)
    {
    }

    @Override
    public String toString()
    {
    }

    private void storeImageDetails() {
    }

    @Override
    //We don't need it - but we are forced to due to interface.
    public int describeContents()
    {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags)
    {
        out.writeString(imageName);
        out.writeString(location);

        out.writeStringArray(keywords);

        out.writeString(imageDate);

        //Can write boolean array but not boolean...
        boolean[] temp = {share};

        out.writeBooleanArray(temp);
        out.writeString(email);

        out.writeInt(rating);
    }

    public static final Parcelable.Creator<SwinImage> CREATOR = new Parcelable.Creator<SwinImage>()
    {

        @Override
        public SwinImage createFromParcel(Parcel parcel)
        {
            return new SwinImage(parcel);
        }

        @Override
        public SwinImage[] newArray(int i)
        {
            return new SwinImage[i];
        }
    };

    //THE PRIVATE CONSTRUCTOR - FOR INTERNAL USE ONLY.
    private SwinImage(Parcel parcel)
    {
        imageName = parcel.readString();
        location = parcel.readString();

        parcel.readStringArray(keywords);

        imageDate = parcel.readString();

        boolean[] tempArr = new boolean[1];
        parcel.readBooleanArray(tempArr);
        share = tempArr[0];

        email = parcel.readString();
        rating = parcel.readInt();
    }

}

Ok... So, in the calling class, I do this:

public void ClickedImage(View v)
{
    Intent i = new Intent(this, MetaDataActivity.class);

    switch (getResources().getResourceEntryName(v.getId()))
    {
        case "burgerView":
            i.putExtra("SENT_IMAGE", burger); //IT IMPLEMENTS PARCLEABLE THEREFORE WE CAN PASS IT WHERE IT LOOKS FOR A PARCEL
            break;
        case "pitaView":
            i.putExtra("SENT_IMAGE", pita);
            break;
        case "pizzaView":
            i.putExtra("SENT_IMAGE", pizza);
            break;
        case "steakView":
            i.putExtra("SENT_IMAGE", steak);
            break;
    }

    startActivityForResult(i, GET_AND_SET_METADATA_REQUEST);
}

I set a breakpoint at the end, and can indeed see that it is in the intent correctly:

The Intent showing an Extra

However, when it comes to getting it:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Log.d("Does", "Does this work");

    Intent i;
    i = getIntent();
    image = i.getExtras().getParcelable("SENT_IMAGE");

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_meta_data);
}

It is never there. The assignment to image crashes the program, and I cannot see through the debugger my SwinImage even existing inside the intent.

What am I doing wrong? Why is it crashing? I have tried for hours solutions (mainly changing how I'm assigning - and some "solutions" have stopped it from crashing, but image is assigned a null)

Can anyone provide some insight? Thanks.

Edit:

I tried moving the getIntent to after onCreate to no avail.

Edit #2: Stack trace:

http://pastebin.com/raw/XJbPxHRv

and types of steak etc:

public class MainActivity extends AppCompatActivity {

    static final int GET_AND_SET_METADATA_REQUEST = 1;  // The request code
    SwinImage burger, pita, pizza, steak;

Solution

  • You can't call getIntent() before super.onCreate() - no Intent is available at that point.

    Move your super call before the getIntent call.

    UPDATE:

    After the above fix, your stack trace shows the issue:

    NullPointerException: Attempt to get length of null array
    at android.os.Parcel.readStringArray(Parcel.java:1026)
    at com.example.kevin.imagemetadata.SwinImage.<init>(SwinImage.java:108)
    

    It seems keywords is null, so attempting to read it from the parcel crashes. Either make sure keywords is never null, or put a boolean that says if keywords can be read or not. Also, per this: How to use writeStringArray() and readStringArray() in a Parcel you should probably use createStringArray instead of readStringArray, a lot simpler.

    A general note: you should always read your crashes stack traces carefully to better understand why your code isn't working as expected, usually it's the best way to fix broken code.