I've got the following class:
public class E implements Parcelable {
#SerializedName("a")
private String a= null;
#SerializedName("b")
private BigDecimal b= null;
#SerializedName("c")
private String c= null;
#SerializedName("d")
private String d= null;
protected E(Parcel in) {
number = in.readString();
expirationYear = in.readString();
expirationMonth = in.readString();
}
public static final Creator<E> CREATOR = new Creator<E>() {
#Override
public E createFromParcel(Parcel in) {
return new E(in);
}
#Override
public E[] newArray(int size) {
return new E[size];
}};
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(number);
dest.writeString(expirationYear);
dest.writeString(expirationMonth);
}
}
How to parcel the data member b? Or better yet, how to parcel boxed types?
As you can see, the writeToParcel method misses the data member b as well as the protected c'tor.
See:
https://medium.com/the-wtf-files/the-mysterious-case-of-the-bundle-and-the-map-7b15279a794e#.sjbki9dss
How to use Parcelable on non-primitive types?
A good way to solve this problem (in my opinion) is to create your class extending BigDecimal and implements Parcelable interface on it.
Related
I have a Parcelable object that has a list of Parcelable objects. I am trying to read that list back after it has been passed from one Activity to the next, but only the first element is "un-bundled"
public class MyBundle implements Parcelable {
private List<Data> dataList;
public static final Parcelable.Creator<MyBundle> CREATOR = new Parcelable.Creator<MyBundle>() {
public MyBundle createFromParcel(Parcel in) {
return new MyBundle(in);
}
public MyBundle[] newArray(int size) {
return new MyBundle[size];
}
};
public MyBundle() {
}
public MyBundle(Parcel in) {
//dataList = new ArrayList<>();
//in.readTypedList(dataList, Data.CREATOR);
dataList = in.createTypedArrayList(Data.CREATOR);
//BOTH have the same result
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if (dataList != null && dataList.size() > 0) {
dest.writeTypedList(dataList);
}
}
}
The data object:
/*BaseObject has the following properties:
UUID uuid;
long databaseId;
createdDate;
modifiedDate;
*/
public class Data extends BaseObject implements Parcelable {
private String name;
private String serial;
private String location;
public Data() {}
private Data(Parcel in) {
String uuidString = in.readString();
if (uuidString == null) return; //this is null!
uuid = UUID.fromString(idString);
databaseId = in.readLong();
createdDate = new Date(in.readLong());
modifiedDate = new Date(in.readLong());
location = in.readString();
name = in.readString();
serial = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uuid.toString());
dest.writeLong(databaseId);
dest.writeLong(createdDate.getTime());
dest.writeLong(modifiedDate.getTime());
dest.writeString(name);
dest.writeString(serial);
}
public static final Parcelable.Creator<Data> CREATOR
= new Parcelable.Creator<Data>() {
public Data createFromParcel(Parcel in) {
return new Data(in);
}
public Data[] newArray(int size) {
return new Data[size];
}
};
}
What I have tried:
Debugging - I can see the first element is read fine but the rest are return null, and they do have values when they are being written
"Android, How to use readTypedList method correctly in a Parcelable class?"
"how to properly implement Parcelable with an ArrayList?"
So this is the answer: My Data parcelable misses the location element when it creates the parcel. This obviously results in some kind of offset error when READING occurs. So the coded solution is as follows:
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uuid.toString());
dest.writeLong(databaseId);
dest.writeLong(createdDate.getTime());
dest.writeLong(modifiedDate.getTime());
dest.writeString(location); /*HERE!*/
dest.writeString(name);
dest.writeString(serial);
}
I hope this helps someone else.
I've a custom parcelable (simplified) that contains a string array:
public class MyClass implements Parcelable {
public static final Creator<MyClass> CREATOR = new Creator<MyClass>() {
public MyClass createFromParcel(Parcel in) {
return new MyClass(in);
}
public MyClass[] newArray(int size) {
return new MyClass[size];
}
};
#SerializedName(“tips”)
private List<String> Tips;
public MyClass() {
Tips = new ArrayList<>();
}
protected Category(Parcel in) {
Tips = in.createStringArrayList();
}
public List<String> getTips() {
return Tips;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringList(Tips);
}
}
I'm trying to pass this parcelable via Intent to another activity. The process is VERY slow and sometimes I get an OOM exception...I don't understand why, I just want to pass a string array...
Save your array into database and pass id of that record.
I have a class with the following structure:
class Example {
Integer age;
String name;
Collection<Example2>examples;
class Example2 {
Integer number;
Collection<String>strings;
}
}
How can I make this class implement Parcelable so that I can send its object across activities.
The simplest way will be to use #AutoParcel and let it handle the heavy lifting for you.
You should take a look at this thread : Android: Making a class parcelable
So your classes should be something like :
class Example implements Parcelable {
Integer age;
String name;
ArrayList<Example2> examples;
public Example(Parcel in) {
examples = new ArrayList<>();
readFromParcel(in);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeList(examples != null ? examples : new ArrayList());
}
private void readFromParcel(Parcel in) {
age = in.readInt();
name = in.readString();
in.readList(examples, Example2.class.getClassLoader());
}
public static final Creator<Example> CREATOR = new Creator<Example>() {
#Override
public Example createFromParcel(Parcel in) {
return new Example(in);
}
#Override
public Example[] newArray(int size) {
return new Example[size];
}
};
}
and
class Example2 implements Parcelable {
Integer number;
ArrayList<String> labels;
public Example2(Parcel in) {
labels = new ArrayList<>();
readFromParcel(in);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInteger(number);
dest.writeList(labels != null ? labels : new ArrayList());
}
#Override
public int describeContents() {
return 0;
}
private void readFromParcel(Parcel in) {
number = in.readInteger();
in.readStringList(labels);
}
public static final Creator<Example2> CREATOR = new Creator<Example2>() {
#Override
public Example2 createFromParcel(Parcel in) {
return new Example2(in);
}
#Override
public Example2[] newArray(int size) {
return new Example2[size];
}
};
}
I trying to pass array of objects via Parcelable. But after the transfer, the data is converted into something strange
The transmitting part:
for (int i=0; i<res.size(); i++) {
Log.d(LOG_TAG, "id = "+res.get(i).id+" weigth = "+res.get(i).weight);
}
ParcelableProducts Checked = new ParcelableProducts();
Checked.setList(res);
intent.putExtra(ParcelableProducts.class.getCanonicalName(), Checked);
The receiving part:
ParcelableProducts res = (ParcelableProducts) data.getParcelableExtra(ParcelableProducts.class.getCanonicalName());
ArrayList<prProduct> prod = res.prod;
for (int i=0; i<prod.size(); i++) {
Log.d(LOG_TAG, "id = "+prod.get(i).id+" weigth = "+prod.get(i).weight);
}
Classes
Parcelable with ArrayList:
public class ParcelableProducts implements Parcelable {
final private static String LOG_TAG = "ParcelableProducts";
public ArrayList<prProduct> prod;
public ParcelableProducts() {
prod = new ArrayList<prProduct>();
}
public void setList(ArrayList<prProduct> _prod){
prod = _prod;
}
public ArrayList<prProduct> getList() {
return prod;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeList(prod);
}
public static final Parcelable.Creator<ParcelableProducts> CREATOR = new Parcelable.Creator<ParcelableProducts>() {
public ParcelableProducts createFromParcel(Parcel in) {
return new ParcelableProducts(in);
}
public ParcelableProducts[] newArray(int size) {
return new ParcelableProducts[size];
}
};
private ParcelableProducts(Parcel parcel) {
prod = new ArrayList<prProduct>();
parcel.readTypedList(prod, prProduct.CREATOR);
}
}
and prProduct:
public class prProduct implements Parcelable {
final static String LOG_TAG = "prProduct";
public float weight;
public int id;
public prProduct(int _id, Float _weight) {
weight = _weight;
id = _id;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeFloat(weight);
parcel.writeInt(id);
}
public static final Parcelable.Creator<prProduct> CREATOR = new Parcelable.Creator<prProduct>() {
public prProduct createFromParcel(Parcel in) {
return new prProduct(in);
}
public prProduct[] newArray(int size) {
return new prProduct[size];
}
};
private prProduct(Parcel parcel) {
weight = parcel.readFloat();
id = parcel.readInt();
}
}
in log:
Transmit: id = 7 weigth = 0.0
Recive: id = 7602278 weigth = 4.2E-44
Off hand I don't see where the data is getting corrupted in transmission, but it will help to clean up your code. Personally I have fixed many weird bugs in the past when I refactor my code to improve readability. First thing you should do is remove the class "ParcelableProducts" because you don't need it. Just pass the ArrayList in the intent directly using the putParcelableArrayListExtra method. Shown here.
Also this is a bit nit picky but you shouldn't directly access your fields. It is better to set them as private and use getters/setters. Also using a for each loop for your logging statement would be a bit cleaner.
A safer PrProduct class.
//Java classes should start with capital letter
public class PrProduct implements Parcelable {
private final static String LOG_TAG = "PrProduct";
private float weight;
private int id;
public prProduct(int id, float weight) {
this.weight = weight;
this.id = id;
}
//Using getters only makes this immutable which is safer since the
//weight/id aren't likely to change.
public float getWeight(){
return weight;}
public int getId(){
return id;}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeFloat(weight);
parcel.writeInt(id);
}
public static final Parcelable.Creator<prProduct> CREATOR = new
Parcelable.Creator<prProduct>() {
public prProduct createFromParcel(Parcel in) {
return new prProduct(in);
}
public prProduct[] newArray(int size) {
return new prProduct[size];
}
};
private prProduct(Parcel parcel) {
weight = parcel.readFloat();
id = parcel.readInt();
}
}
//A sample for each loop
for(PrProduct product: prod)
Log.d(LOG_TAG, "weight=" + product.getWeight() + " id=" + product.getId());
Why do you need to create the object ParcelableProducts that implements Parcelable? I think you can just pass the arraylist directly using putParcelableArrayListExtra method from the intent?
I have a class that contains data i want to pass it between intents, this class have arraylist that contains another class objects. this is my class
public class ParsedData implements Parcelable {
public String error;
public float protectionLevel;
public int protectionLevelColor;
public double lastBackup;
public boolean compressedType;
public Long driveFreeSpaceSize;
ArrayList<Item>Items = new ArrayList<Item>();
}
class Item {
public String name;
public float percentage;
public int files;
public long size;
}
how can i send this class between intents ?
you can let your class Item implements the Serializable interface, and use Intent.putExtra(String, Serializable). Since ArrayList implements also the Serializable interface, you can pass the whole Items object.
This may be your problem:
Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator interface.
Alternatively, I'd try to have Item implement Parcelable, as well.
The fail-safe alternative is to write your data structure into a JSON string, which also allows you to pass the data to other applications that don't have access to your ParsedData class.
You may take a look at Intent.putExtra(String name, Parcelable object) and implement the parcelable interface in your class.
i have found the answer after all. thanks all how helped me
this is the answer:
import android.os.Parcel;
import android.os.Parcelable;
public class ParsedData implements Parcelable {
public String error;
public float protectionLevel;
public int protectionLevelColor;
public double lastBackup;
public boolean compressedType;
public Long statusSendTime;
ArrayList<Item>Items = new ArrayList<Item>();
//---------------------Constructors---------------------------
public ParsedData() { ; };
public ParsedData(Parcel in) {
readFromParcel(in);
}
//------------------------------------------------------------
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(error);
dest.writeFloat(protectionLevel);
dest.writeInt(protectionLevelColor);
dest.writeDouble(lastBackup);
dest.writeByte((byte) (compressedType ? 1 : 0));
dest.writeLong(statusSendTime);
dest.writeList(Items);
}
private void readFromParcel(Parcel in) {
error = in.readString();
protectionLevel = in.readFloat();
protectionLevelColor = in.readInt();
lastBackup = in.readDouble();
compressedType =in.readByte() == 1;
statusSendTime = in.readLong();
in.readList(Items,Item.class.getClassLoader() );
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public ParsedData createFromParcel(Parcel in) {
return new ParsedData(in);
}
public ParsedData[] newArray(int size) {
return new ParsedData[size];
}
};
}
class Item implements Parcelable {
public String name;
public float percentage;
//---------------------Constructors---------------------------
public Item() {
}
public Item(Parcel in) {
readFromParcel(in);
}
//------------------------------------------------------------
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeFloat(percentage);
}
public static final Creator<Item> CREATOR = new Creator<Item>() {
public Item createFromParcel(Parcel source) {
return new Item(source);
}
public Item[] newArray(int size) {
return new Item[size];
}
};
private void readFromParcel(Parcel in) {
this.name = in.readString();
this.percentage = in.readFloat();
}
}
and in the caller activity
ParsedData data = new PArsedData();
Intent intentBreakDown = new Intent(this,BreakDownBarActivity.class);
intentBreakDown.putExtra("data", data);
startActivity(intentBreakDown);
in the called activity(BreakDownBarActivity in my case)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.breakdownbar);
Bundle b = getIntent().getExtras();
ParsedData data = (ParsedData)b.getParcelable("data");
}