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:
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;
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.