I want to make a custom entity class Parcelable.. I have some fields in it: a String[] and another custom entity object (which is parcelable).. I want to know how to read and write these objects and lists..
public class CustomEntity implements Parcelable {
private int number;
private String[] urls;
private AnotherEntity object;
public CustomEntity(Parcel in) {
number = in.readInt();
// how should I read urls?
// how should I read object?
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(number);
// how should I write urls?
// how should I write object?
}
}
For a String[] you can use the API
parcel.writeStringArray(url)
For AnotherEntity you need to extend it with Parcelable again
parcel.writeParcelable();
https://github.com/mcharmas/android-parcelable-intellij-plugin use this plugin!
Your AnotherEntity must implemented Parcelable too!
I definitely think you should NOT handle the boilerplate yourself.
There are libraries around like Parceler where with only one annotation on your POJO and one line like Parcel.wrap or Parcel.unwrap you can do instant serialization.
Related
I know putExtra can be used to pass objects/strings around between actives. But I am trying you put an ArrayList of objects like ArrayList<Foo> in putExtra
Is this possible?
No it isn't. You'll need to serialize your object into some kind of string representation. One possible string representation is JSON, and one of the easiest ways to serialize to/from JSON in android, if you ask me, is through Google GSON.
Also if you're just passing objects around then Parcelable was designed for this. It requires a little more effort to use than using Java's native serialization, but it's way faster (and I mean way, WAY faster).
From Docs :
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
}
You can use
intent.putParcelableArrayListExtra() for passing Arraylist in intent.
Refer to http://developer.android.com/reference/android/content/Intent.html#putParcelableArrayListExtra(java.lang.String, java.util.ArrayList)
EDIT :
one more link : Help with passing ArrayList and parcelable Activity
Only for very limited and particular types of "Foo". If i recall correctly Double and Long (or maybe it was Integer?) being those types. There might be a way to smuggle a more generic ArrayList through by encapsulating it in some Serializable Object, but I'm not sure about that.
I happen to know what if my class Info which implements Parcelable has empty writeToParcel() method, Bundle.putParcelableArrayList() and Bundle.getParcelableArrayList() methods still work on ArrayList< Info>.
public class Info implements Parcelable
{
public int row;
public int column;
public int describeContents()
{
return 0;
}
public void writeToParcel(Parcel out, int flags)
{
// Left empty!
}
}
So the question is why? When I really should implement writeToParcel method as API documentation and books instruct?
The Android Bundle class does not follow the same protocol that is followed during IPC marshaling. Through reflection, a class that implements Bundle will simply read & write the Parcelable object into its own internal mapping. So, whatever properties you define in your Parcelable derived class will be used.
On the contrary, if you're using the IPC Marshalling protocol - e.g. passing your Info object from one activity to another - this is when you need to implement a specific writeToParcelable method and the appropriate constructor.
I'm asking this question: instread of giving a string, a int and so on, can we push a custom object during the creation fo a new Intent?
newActivity.PutExtra("JsonDataResult", business.getJSON());
In fact I have one object constructed thanks to a JSON (from webrequest) , I parse it and I put it on an object.
At this point I'm passing the string returned from the webrequest to another intent but the parsing takes a long time tu be done, so it could be super-cool the ability to pass custom object with intent.
EDIT : I'm using monodroid / xamarin, so
Android.OS.IParcelable cannot be implemented,
Java.IO.ISerializable cannot be implemented.
You can either let your custom classes implement Parcelable (Google says its faster, but you have to do more coding) or Serializable.
Then add your objects to a bundle (or to the "extra"):
Bundle b = new Bundle()
b.putParcelable("myObject",myObject);
b.putSerializable("myObject",myObject);
For info to Parcelablecheckout this
And if you're interested in the difference between Parcelable and Serializable in more detail check out this
I personally prefer the usage of Serializable for simple object-passing, since the code ist not spoiled with so much code.
Edit: ok isn't your question very similar to this then?
As you've specified you're using Monodroid, it looks like it's not straightforward. I did a quick search and found this forum post
Which listed the following solutions to this problem in Monodroid:
Store the custom Object to be passed as a global variable somewhere, and just read it from your second activity
Which is a bit messy and bad practice, but would work.
Or
serialize your class to a string and send the string to the second Activity
Which will be a little more hard work, but better practice
This is an example how to create a Parcelable class:
public class Person implements Parcelable {
private String name;
private String surname;
private String email;
// Get and Set methods
#Override
public int describeContents() {
return hashCode();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(surname);
dest.writeString(email);
}
// We reconstruct the object reading from the Parcel data
public Person(Parcel p) {
name = p.readString();
surname = p.readString();
email = p.readString();
}
public Person() {}
// We need to add a Creator
public static final Parcelable.Creator<person> CREATOR = new Parcelable.Creator<person>() {
#Override
public Person createFromParcel(Parcel parcel) {
return new Person(parcel);
}
#Override
public Person[] newArray(int size) {
return new Person[size];
}
};
Give a look here if you want to use Parcelable.
So i know it is recommended to use Parcelable instead of Serializable in android, because it is faster.
My question is: is that impossible to avoid using Serializable right?
If I have a custom object i want to serialize, let's say I have the following class definition
public class Person {
String name;
int Age;
...
....
}
Making this parcelable is easy, because the Person class contains the types parcel.write*() supports, i.e. there is parcel.writeString and parcel.writeInt
Now, what if the Person class is the following:
public class PersonTwo {
MyCustomObj customObj;
String name;
int Age;
...
....
}
How am I suppose to parcel the MyCustomObj object??
It seems I need to use serializable again? but again, I thought it is SLOW to use serializable, and seems we have no choice but to use it in this case.
I don't understand
can someone tell me how I would parcel PersonTwo in this case?
The link given by Ajay is the exact what you are looking for, how you can do it.
Well, what you can do is implement Parcelable to your CustomObject1 and create a Parcelable class for it and then you can use that Parcelable class to Parcel it inside another Parcelable class that will Parcel both the CustomObjects.
public class CustomObject1 implements Parcelable {
// parcelable code CustomObject1
}
public class CustomObject2 implements Parcelable {
private CustomObject1 obj1;
// add CustomObject1 here with getter setter
// parcelable code for CustomObject2
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(obj1, flags);
}
private void readFromParcel(Parcel in) {
obj1 = in.readParcelable(CustomObject1.class.getClassLoader());
}
............
}
You need to make MyCustomObj parcelable.
All the composite objects should also be Parcelable. In case, you want to skip an object then don't use it writeToParcel method.
I came to point where Parcelable is an issue for me.
On Android 4.3, I am getting unmarhalling exception, when passing data between
Activities as Parcelable. It works OK on Android 4.0, 4.2 or 4.4.
It should work when changed to Serializable, even though, it is slower.
Let me first give you the whole picture: I am developing a location based application, that invokes a constant recreation and exchange of objects, among several activities and services. The necessary data to create the objects being exchanged, is stored in an SQLite database, that in its turn gets populated by retrieving data from a remote SQL database.
It got quickly obvious, that passing raw attributes of an object to activities/services (via intents), was a huge coding overhead, diminishing every extension prospects the application might have. So, soon i decided to extend my main object class to implement a Parcelable one, as shown below:
public class MyProduct implements Parcelable {
//MyProduct Attributes
private int myProductId;
private String myProductDescription;
private float myProductRadius;
//More attributes...
public MyProduct() {
myProductId=-1;
myProductDescription="defaultProductDescription";
myProductRadius=10;
//More attributes
}
public int describeContents(){
return 0;
}
// write your object's data to the passed-in Parcel
public void writeToParcel(Parcel out, int flags){
//Product attributes
try{
out.writeInt(myProductId);
out.writeString(myProductDescription);
out.writeFloat(myProductRadius);
//More attributes
}
catch (Exception e){}
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<MyProduct> CREATOR = new Parcelable.Creator<MyProduct>() {
//public class MyCreator implements Parcelable.Creator<MyProduct> {
public MyProduct createFromParcel(Parcel in) {
return new MyProduct(in);
}
public MyProduct[] newArray(int size) {
return new MyProduct[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private MyProduct(Parcel in) {
//in.readParcelable(MyProduct.class.getClassLoader());
try{
//MyProduct.class.getClassLoader();
myProductId=in.readInt();
myProductDescription=in.readString();
myProductRadius=in.readFloat();
//More attributes
}
catch(Exception e){}
}
//Setters and Getters
}//endOfMyProduct.class
Although i checked every data entry to the parcel fields, the following exception keeps spawning:
01-05 19:35:11.570: ERROR/Parcel(59): Class not found when unmarshalling: com.nifo.distribution.MyProduct, e: java.lang.ClassNotFoundException: com.nifo.distribution.MyProduct
For this reason, i consider of the MyProduct.class implementing serializable, hoping that it will turn to be a more error-forgiving structure. What would be the pros and cons of such alternation in the case described above?