At the moment I have the problem to pass an ArrayList<MyClass> from one activity to another. I tried to implement Parcelable in MyClass and use an intent in the activity but it seems that I did something wrong. When I call startActivity with the intent the window of the app freezes and I get the Error "!!! Failed Bender Transaction !!!". I've read here and on some other places that the size of the transaction may cause the error. MyClass holds one Image. In the moment startActivity is called the ArrayList holds five elements with one bitmap for each element. The size of all images together is below 70kb.
Here is my actual code:
public class MyClass implements Parcelable {
public enum Type {
VIDEO, AUDIO
}
private int id;
private String name;
private String url;
private double longitude;
private double latitude;
private double gpsDistance;
private String description;
private String thumb;
private Bitmap thumbpic;
private Type type;
public MyClass() {
this.gpsDistance = 0;
}
public MyClass(Parcel in) {
readFromParcel(in);
}
/* Setter & Getter */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(url);
dest.writeDouble(longitude);
dest.writeDouble(latitude);
dest.writeDouble(gpsDistance);
dest.writeString(description);
dest.writeString(thumb);
dest.writeParcelable(thumbpic, flags);
dest.writeString((type == null) ? "" : type.name());
}
private void readFromParcel(Parcel in) {
this.id = in.readInt();
this.name = in.readString();
this.url = in.readString();
this.longitude = in.readDouble();
this.latitude = in.readDouble();
this.gpsDistance = in.readDouble();
this.description = in.readString();
this.thumb = in.readString();
this.thumbpic = (Bitmap) in.readParcelable(getClass().getClassLoader());
try {
type = Type.valueOf(in.readString());
} catch (IllegalArgumentException x) {
type = null;
}
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public MyClass createFromParcel(Parcel in) {
return new MyClass(in);
}
public MyClass[] newArray(int size) {
return new MyClass[size];
}
};
}
Some code snippets from the activity (MainActivity) which starts the second one (ListActivity)
ArrayList<Content> contentElements = new ArrayList<Content>();
Intent intent = new Intent(MainActivity.this,ListActivity.class);
intent.putParcelableArrayListExtra("content", contentElements);
The handling in the ListActivity
Intent i = getIntent();
contentElements= i.getParcelableArrayListExtra("content");
Does someone have an idea what caused this problem and have solution or an alternative approach?
Thanks a lot!
Related
I am trying to make a list of objects that are all of an abstract class, but each are there own class. This list needs to persistent so I figured I implement parcelable since I have done so in the past. Only not with different classes all of an abstract class.
I tried just making the abstract class parcelable but that can't have a creator that I am used to because (of course) you can't create an instance of it (because it is abstract). Reading around I noticed that people said you dont need a constructor in the abstract class, just in the subclasses.
AbstractFocusPower class
public abstract class AbstractFocusPower implements Parcelable {
private transient AppExtension app;
private ImplementSchool school;
private String name;
private int duration;
private int cost;
private int altCost;
private int requiredLevel;
private boolean isSelected;
private boolean isResonant;
private int nofSpirtBonusUsed;
/**
* Constructor for Focus Power with no alternative cost
*/
public AbstractFocusPower(AppExtension app, ImplementSchool school, String name, int requiredLevel, int duration, int cost, boolean isSelected) {
this.app = app;
this.school = school;
this.name = name;
this.requiredLevel = requiredLevel;
this.duration = duration;
this.cost = cost;
this.altCost = -1;
this.isSelected = isSelected;
this.isResonant = false;
}
// I cut out the other constructors
public abstract AbstractFocusPower makeCopy();
public abstract String getDescription();
// I cut out the getters and setters
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.school == null ? -1 : this.school.ordinal());
dest.writeString(this.name);
dest.writeInt(this.duration);
dest.writeInt(this.cost);
dest.writeInt(this.altCost);
dest.writeInt(this.requiredLevel);
dest.writeByte(this.isSelected ? (byte) 1 : (byte) 0);
dest.writeByte(this.isResonant ? (byte) 1 : (byte) 0);
dest.writeInt(this.nofSpirtBonusUsed);
}
protected AbstractFocusPower(Parcel in) {
int tmpSchool = in.readInt();
this.school = tmpSchool == -1 ? null : ImplementSchool.values()[tmpSchool];
this.name = in.readString();
this.duration = in.readInt();
this.cost = in.readInt();
this.altCost = in.readInt();
this.requiredLevel = in.readInt();
this.isSelected = in.readByte() != 0;
this.isResonant = in.readByte() != 0;
this.nofSpirtBonusUsed = in.readInt();
}
Sample subclass
public class AegisFocusPower extends AbstractFocusPower {
public AegisFocusPower(AppExtension app) {
super(app, ImplementSchool.ABJURATION, app.getString(R.string.focus_power_name_aegis), 0, 1, 1, false);
}
#Override
public String getDescription() {
return getApp().getString(R.string.focus_power_desc_aegis, (1+((int) Math.floor(getApp().getCurrentCharacter().getOccultistLevel()/6.0))));
}
#Override
public AegisFocusPower makeCopy() {
return new AegisFocusPower(getApp());
}
public AegisFocusPower(Parcel in) {
super(in);
}
public static final Parcelable.Creator<AegisFocusPower> CREATOR = new Parcelable.Creator<AegisFocusPower>() {
public AegisFocusPower createFromParcel(Parcel in) {
return new AegisFocusPower (in);
}
public AegisFocusPower [] newArray(int size) {
return new AegisFocusPower[size];
}
};
}
Code where I use it
Gson gsonFocusPowers = new Gson();
String jsonFocusPowers = sharedPreferences.getString(FOCUS_POWERS_GSON, null);
Type typeFocusPower = new TypeToken<ArrayList<AbstractFocusPower>>() {
}.getType();
ArrayList<AbstractFocusPower> focusPowers;
focusPowers = gsonFocusPowers.fromJson(jsonFocusPowers, typeFocusPower);
if (focusPowers != null) {
this.focusPowers.addAll(checkForNewFocusPowers(focusPowers));
} else {
this.focusPowers = getNewFocusPowerList();
}
Unfortunately this gives me an error which I don't know how to fix.
java.lang.RuntimeException: Unable to create application nl.rekijan.occultistmentalfocushelper.AppExtension: java.lang.RuntimeException: Unable to invoke no-args constructor for class nl.rekijan.occultistmentalfocushelper.mvc.focuspowers.AbstractFocusPower. Registering an InstanceCreator with Gson for this type may fix this problem.
Edit: Not sure why that post is a duplicate. For starters it doesn't have an accepted answer. The answer requires a 3rd party library. The question isn't about multiple subclasses under a single abstract.
have you tried registering a type adapter, something like Using Gson and Abstract Classes ? I always add adapters both for specific formatting (for dates, big decimals, anything where you usually require a very specific format) but also for sub-classing.
In this case however, no adapter is needed, this is.. straight on?
public abstract class AbstractFocusPower implements Parcelable {
// just some property needed to be pushed through a constructor
protected final String myString;
protected AbstractFocusPower(String myString) {
this.myString = myString;
}
}
and then the impl (yeah added toString(), hashCode() and equals() the way I like them to be in domain objects..):
public class AegisFocusPower extends AbstractFocusPower {
boolean imParcelled;
public AegisFocusPower(String myString) {
super(myString);
}
#Override //yup the interface impl
public void parcelMe() {
imParcelled = true;
}
#Override
public String toString() {
return new StringBuilder("{ imParcelled : ").append(imParcelled).append(", myString : ").append(myString).append(" }").toString();
}
#Override
public int hashCode() {
return toString().hashCode();
}
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other == null || !(other instanceof AegisFocusPower)) {
return false;
} else {
return other.hashCode() == hashCode();
}
}
}
and then I can run the following junit :
#Test
public void AegisFocusPowerToJsonAndBack(){
// single instance
AegisFocusPower ea = new AegisFocusPower("apa");
String json = GSON.toJson(ea);
assertEquals("{\"imParcelled\":\"false\",\"myString\":\"apa\"}", json);
AegisFocusPower backAtYa = (AegisFocusPower) GSON.fromJson(json, AegisFocusPower.class);
assertEquals(backAtYa, ea);
// A list
AegisFocusPower ea2 = new AegisFocusPower("bepa");
AegisFocusPower ea3 = new AegisFocusPower("cepa");
List<AegisFocusPower> powerList = new ArrayList<>();
powerList.add(ea2);
powerList.add(ea3);
String jsonList = GSON.toJson(powerList);
assertEquals("[{\"imParcelled\":\"false\",\"myString\":\"bepa\"},{\"imParcelled\":\"false\",\"myString\":\"cepa\"}]", jsonList);
List<AegisFocusPower> backAtYaz = Arrays.asList(GSON.fromJson(jsonList,AegisFocusPower[].class));
assertEquals(backAtYaz.get(0), ea2);
assertEquals(backAtYaz.get(1), ea3);
}
whereas GSON is initialized simply like
private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(Boolean.class, new JsonBooleanDeAndSerializer()).create();
and the type adapter registered for booleans which I use is irrelevant for your problem.
This is.. simple enough and would work for you too?
Check your imports. You may have mistakenly imported wrong class in your pojo. i.e. I have imported android.net.TransportInfo instead of my own TransportInfo class
I'm trying to pass a list of images to another activity via a Parcelable object in Android. I can convert the images down to a byte[] array fine.
However, I've got a list of these images so there's going to be more than one byte[] array.
Here is my code so far.
public class InvalidItem implements Parcelable {
public String id;
public ArrayList<byte[]> imageList = new ArrayList<>();
public InvalidItem(String id) {
this.id = id;
}
public InvalidItem(Parcel in) {
String[] data = new String[22];
in.readStringArray(data);
this.id= data[0];
this.imageList = data[1];
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[]{
this.id,
String.valueOf(this.imageList)
});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public InvalidItem createFromParcel(Parcel in) {
return new InvalidItem(in);
}
public InvalidItem[] newArray(int size) {
return new InvalidItem[size];
}
};
}
As you can see I write the string array which would work for one byte[] array. Is there a way I could have a list of byte[] arrays that I decode into one string and then encode when I want to show the images?
I've tried looking into solutions and people have suggested passing it in the bundle.
However, this application follows a step by step process and requires an object to store the data in.
I have an error when using a Parcelable Class.
I'm trying to pass an image as a ByteArray between activities, and eventually to a remote webservice.
java.lang.ClassNotFoundException: ...
Class not found when unmarshalling:
import java.util.UUID;
public class Property implements Parcelable {
#SerializedName("id")
#NonNull
private final String mId;
protected byte[] mImage;
public byte[] getmImage() { return mImage; }
public void setmImage(byte[] image){ mImage = image; }
#SerializedName("generalInformation")
private GeneralInformation mGeneralInformation;
#NonNull
public GeneralInformation getGeneralInformation() {
return mGeneralInformation;
}
public void setGeneralInformation(#NonNull final GeneralInformation generalInformation) {
mGeneralInformation = generalInformation;
}
#NonNull
public String getId() {
return mId;
}
#Override
public boolean equals(final Object o) {
return (o instanceof Property) && ((Property) o).mId.equals(mId);
}
#Override
public int hashCode() {
return mId.hashCode();
}
public static Property create() {
final Property model = new Property(UUID.randomUUID().toString());
model.setGeneralInformation(new GeneralInformation());
return model;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(#NonNull final Parcel dest, final int flags) {
if(mImage != null) {
dest.writeInt(mImage.length);
dest.writeByteArray(mImage);
}
dest.writeString(mId);
dest.writeParcelable(mGeneralInformation, 0);
}
private Property(#NonNull final String id) {
mId = id;
}
protected Property(final Parcel in) {
if(mImage != null)
{
mImage = new byte[in.readInt()];
in.createByteArray();
}
mId = in.readString();
mGeneralInformation = in.readParcelable(GeneralInformation.class.getClassLoader());
}
public static final Parcelable.Creator<Property> CREATOR = new Parcelable.Creator<Property>() {
public Property createFromParcel(#NonNull final Parcel source) {
return new Property(source);
}
#NonNull
public Property[] newArray(final int size) {
return new Property[size];
}
};
}
Now I have a very limited understanding of the problem(s) I have with this class.
mImage is null when reading the Parcel. (Even when I know for sure that the byteArray is not null when I assign it to the Parcel.) I have tried to initialize mImage in its declaration so it not null but then I have that Class not found when unmarshalling error...
I'm almost sure the problem lies in
protected Property(final Parcel in) {
if(mImage != null)
{
mImage = new byte[in.readInt()];
in.createByteArray();
}
But I don't know how to fix it.
I'm lost for 2 days with this thing :/
Please see the below code for constructor with Parcel object.
protected Property(final Parcel in) {
mImage = new byte[in.readInt()];
in.readByteArray(mImage); // this will read the byte array from Parcel object(in) and store the value in mImage member variable.
mId = in.readString();
mGeneralInformation = in.readParcelable(GeneralInformation.class.getClassLoader());
}
Activity 1, from where I send my Parcelable object:
Intent intent = new Intent(JobFieldAttribute.this, JobCamera.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle mBundle = new Bundle();
mBundle.putParcelable("FieldData", fieldData);
mBundle.putSerializable("JobTransaction",jobTransaction);
mBundle.putString("imgPos", 0+"");
intent.putExtra("parce",mBundle);
startActivity(intent);
My object class:
public class FieldData implements Parcelable {
private Integer id;
private String value;
private Integer job_transaction_id;
private Integer field_attribute_master_id;
private Boolean required;
private View view;
private String viewType;
private String viewLabel;
private String viewSubLabel;
private String viewHelpText;
//All Getter setter methods
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(0);
dest.writeString(value);
try{
dest.writeInt(job_transaction_id);
}
catch(Exception e){dest.writeInt(0);}
dest.writeInt(field_attribute_master_id);
try{
dest.writeByte((byte) (required ? 1 : 0));
}
catch(Exception e){dest.writeByte((byte)0);}
try{
dest.writeString(viewType);
}
catch(Exception e){dest.writeString("NOVIEWTYPE");}
try{
dest.writeString(viewLabel);
}
catch(Exception e){dest.writeString("NO LABEL");}
try{
dest.writeString(viewSubLabel);
}
catch(Exception e){dest.writeString("NO SUB LABEL");}
try{
dest.writeString(viewHelpText);
}
catch(Exception e){dest.writeString("NO HELP TEXT");}
}
public static final Parcelable.Creator<FieldData> CREATOR = new Parcelable.Creator<FieldData>() {
#Override
public FieldData createFromParcel(Parcel in) {
FieldData fieldData = new FieldData();
fieldData.id = in.readInt();
Log.i("Pracel in", ">> " + in.readString());
fieldData.value = in.readString();
fieldData.job_transaction_id = in.readInt();
fieldData.field_attribute_master_id = in.readInt();
fieldData.required = in.readByte() != 0;
fieldData.viewType = in.readString();
fieldData.viewLabel = in.readString();
fieldData.viewSubLabel = in.readString();
fieldData.viewHelpText = in.readString();
return fieldData;
}
#Override
public FieldData[] newArray(int size) {
return new FieldData[size];
}
};
}
My second activity, which receives this Parcelable object:
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_job_camera);
FieldData fieldData = (FieldData) getIntent().getParcelableExtra("fieldData");
When i print my fieldData object, i get a NullPointerException. I cannot understand the reason for this error.
What am i doing wrong?
I am a newbie at android development and using Parcelable interface for passing object via Intent.
Please help.
You are putting FieldData but trying to get back fieldData. Combine it with #Dmitry Zaitsev's answer: getIntent().getBundleExtra("parce").getParcelableExtra("FieldData");
You're putting Bundle to your Intent extras, not FieldData directly. So, your code should look as follows:
getIntent().getBundleExtra("parce").getParcelableExtra("fieldData");
I have a bit trouble implementing Parcelable. Here's how I did it:
public class Player implements Parcelable{
String name;
int score;
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(score);
}
public Player(Parcel source){
score = source.readInt();
name = source.readString();
}
}
public class MyCreator implements Parcelable.Creator<Player> {
#Override
public Player createFromParcel(Parcel source) {
return new Player(source);
}
#Override
public Player[] newArray(int size) {
return new Player[size];
}
}
This was the whole code implementing Parcelable. Now I'm trying to create a new class object:
Player newPlayer = new Player(null);
newPlayer.name = text;
newPlayer.score = 0;
playersParceledData.add(newPlayer);
zacniIgro.putParcelableArrayListExtra("parceledData", playersParceledData);
This is the line that is bothering me:
Player newPlayer = new Player(null);
Is the fact that I just insrted "null" okay? Or do I have to insert something else between those ()? I was following this example and this isn't explained in it. It says that a new object should be created like this:
Player newPlayer = new Player();
But I am not allowed to do this since I made a constructor.
Create an additional constructor for use cases you're not using Parcel to construct your object, for example
public class Player implements Parcelable{
/* ... */
public Player(Parcel source){
/* ... */
}
public Player(int score, String name){
this.score = score;
this.name = name;
}
}
Then you can construct objects both from Parcel and using an int and an String:
final Player aPlayer = new Player(10000, "SomeRandomPlayerName");
Also, you read the int and the String in inverse order as you write them.