Few days back I had a requirement to send a ArrayList of my Custom Class Objects through Android Intent, I guess most of you also find this requirement now and then. I never thought it can be that tricky.
There are built in functions in Intent to send ArrayList of primitive objects e.g. String, Integer, but when it comes to Custom Data Handling Objects, BOOM… you need to take that extra pain!
Android has defined a new light weight IPC (Inter Process Communication) data structure called Parcel, where you can flatten your objects in byte stream, same as J2SDK’s Serialization concept.
So let’s come back to my original requirement, I had a Data Handling class, which groups together a set of information-
public class ParcelData {
int id;
String name;
String desc;
String[] cities = {"suwon", "delhi"};
}
I want an ArrayList<ParcelData> of Data Handling objects to be able to pass through Intent. To do that, I can’t use the ParcelData as it is; you need to implement an Interface android.os.Parcelable which will make Objects of this class Parcelable. So you need to define your data handling class as-
public class ParcelData implements Parcelable {
int id;
String name;
String desc;
String[] cities = {"suwon", "delhi"};
}
You need to overwrite 2 methods of android.os.Parcelable Interface-
- describeContents()- define the kind of object you are going to Parcel, you can use the hashCode() here.
- writeToParcel(Parcel dest, int flags)- actual object serialization/flattening happens here. You need to individually Parcel each element of the object.
public void writeToParcel(Parcel dest, int flags) {
Log.v(TAG, "writeToParcel..."+ flags);
dest.writeInt(id);
dest.writeString(name);
dest.writeString(desc);
dest.writeStringArray(cities);
}
Note: Don’t try things like, dest.writeValue(this) to flatten the complete Object at a time (I don’t think all people have some weird imaginations like me, so you’ll never try this, right ?…) that will end up in recursive call of writeToParcel().
Up to this point you are done with the required steps to flatten/serialize your custom object.
Next, you need to add steps to un-marshal/un-flatten/de-serialize (whatever you call it) your custom data objects from Parcel. You need to define one weird variable called CREATOR of type Parcelable.Creator. If you don’t do that, Android framework will throw exception-
Parcelable protocol requires a Parcelable.Creator object called CREATOR
Following is a sample implementation of Parcelable.Creator<ParcelData> interface for my class ParcelData.java
/**
* It will be required during un-marshaling data stored in a Parcel
* @author prasanta
*/
public class MyCreator implements Parcelable.Creator<ParcelData> {
public ParcelData createFromParcel(Parcel source) {
return new ParcelData(source);
}
public ParcelData[] newArray(int size) {
return new ParcelData[size];
}
}
You need to define a Constructor in ParcelData.java which puts together all parceled data back
/**
* This will be used only by the MyCreator
* @param source
*/
public ParcelData(Parcel source){
/*
* Reconstruct from the Parcel
*/
Log.v(TAG, "ParcelData(Parcel source): time to put back parcel data");
id = source.readInt();
name = source.readString();
desc = source.readString();
source.readStringArray(cities);
}
You can deserve some rest now…...as you are done with it. So now you can use, something like
Intent parcelIntent = new Intent(this, ParcelActivity.class);
ArrayList<ParcelData> dataList = new ArrayList<ParcelData>();
/*
* Add elements in dataLists e.g.
* ParcelData pd1 = new ParcelData();
* ParcelData pd2 = new ParcelData();
*
* fill in data in pd1 and pd2
*
* dataLists.add(pd1);
* dataLists.add(pd2);
*/
parcelIntent.putParcelableArrayListExtra("custom_data_list", data);
So, how hard is that? :-). Share your comments, I'm listening.
good example......Thanks
ReplyDelete- santhana
Very well explained....thankyou!! :)
ReplyDeleteOne more thing wat if I have a Parceable object that has List instanceVariable?
Hi Anandram,
ReplyDeleteif that list instance variable contains premitive objects, you don't have to do anything special i.e. probably need to call writeList() to write to parcel.
But if the parcelable object contains List of Custom objects, you need to make your Custom Class also Parcelable and need to use-
writeTypedList()
and
readList(listInstance, .class.getClassLoader());
Hope this helps.
Hi really a nice article. Good work. Thank you :)
ReplyDeletethis is really helpful.. in fact i was very much confused initially.. thanks a lot for posting this wonderful tutorial..
ReplyDeleteExcellent - i tried to write my parcelable by following the SDK doc, but it was riddled with uncertainty. I followed your technique and had it written in 15 minutes and debugged in 5.
ReplyDeleteYou might want to include a non-native type like Date and null member data. I had a class similar to yours with an uninitialized date.
Hi Bob,
ReplyDeleteappreciate your comments.
Probably I'll write Part 2 of this which will include a set of advance data structures and your custom classes.
Let's see when I get time to do that :-)
Thanks,
Prasanta
Hi prashant
ReplyDeletei gotta pass an object in intent it is of Messgae[] type(i guess you know this). i did whatever you said and the only change was source.writeArray(Object[] val) where am passing my object of Message[] type. Now, what code to be overwritten on the other side to handle this.Please respond asap
Hi Vivek,
ReplyDeleteI guess you are talking about android.os.Message.
Message internally implements Parcelable, so you need not to worry for its internal data marshaling/un-marshaling.
If you are using an array of Message[] msgs-
to write-
dest.writeArray(msgs);
to read-
source.readArray(ParcelData..class.getClassLoader());
I hope this will work.
Thanks,
Prasanta
I'm having trouble recovering the data in the other activity:
ReplyDelete//onCreate
ArrayList listaCadastradaArray = (ArrayList) getIntent().getParcelableArrayExtra("listaCadastrada");
it says it can't cast from Parcelable[] to ArrayList
Roger: if you remove the cast your code should work, I had the same problem. I guess you can directly assign the parcelable arraylist to your custom arraylist...
ReplyDeleteThanks for sharing, Prasanta!
ReplyDeleteCheers,
Torsten
Hey Prasanta Paul,
ReplyDeleteI appreciate your help.
Cheers,
Ritesh
Hi, at first i would like to thank you for your example! At second i have a little problem with recovering the data from intent. Could you please tell me, where is mistake?
ReplyDeleteIn activity A I do this:
ArrayList tmpRecordAll = getAllRecords();
Intent intentAllData = new Intent(DATA_BROADCAST);
intentAllData.putParcelableArrayListExtra("AllRecordsByID", tmpRecordAll);
sendBroadcast(intentAllData);
In actvity B I have this:
ArrayList tmpArrayListID = intent.getParcelableArrayListExtra("AllRecordsByID");
and after that the tmpArrayListID is empty...
thanks for help.
Sorry for my previous comment. Everthing is working fine, error was elsewere :)
ReplyDeleteI there some method in Parcel so I can write a TreeMap in a Parcel?
ReplyDeleteHow do you handle a nested complex object inside ParcelData i.e. ArrayList where T is a complex object? How would the writeToParcel look?
ReplyDeleteWhere is MyCreator used in the scheme of things?
ReplyDeletewow. i like the way you put these tiny puzzle-pieces together with that very simplistic and concise explanation. i have a little query though.
ReplyDeletehow would you actually know which string is which? for example, like in your class, you will have multiple similar variables, let's say you have 5 strings..how would you know that this is the 'name' string or this is the 'gender' string..or things like that, when the way to retrieve them is only through the method readString()? would you have to retrieve them in a sequence exactly similar to how you wrote them? this is confusing.
thats the only little missing piece in this mind-puzzle that i have inside my head about this parcelable interface..
thank you so much sir. :)
could anybody help me? ^^
This post - http://idlesun.wordpress.com/2011/07/15/android-parcelable-example-2-sub-object-and-list/ answered my questions. He has an example 1 post out there as well.
ReplyDeleteJust to echo what Vivek asked, I'm looking to pass a Date. How would I go about doing that?
ReplyDeleteExcellent example! Thank you!
ReplyDelete"static final: must used for CREATOR cariable
ReplyDeletepublic static final Parcelable.Creator CREATOR=...
in parceldata.java
thanx a lot Prasanta .. u r an angel :)
ReplyDelete-Ash
Nice One. You helped me at a critical situation
ReplyDeleteVery useful articular for me
ReplyDeleteThanks a lot
dharmendra.sahu09@gmail.com
Hi ,
ReplyDeleteIs it possible to pass a pointer to structure in binders between proxy and native .
Regards,
Raj
Thanks man
ReplyDeleteGreat Job.. thanks!!
ReplyDeletePrasanta, thanks for writing this. Very helpful.
ReplyDeleteHi Prasantha,
ReplyDeleteis it possible for us to pass the socket, inputstream and output stream the same way ? Kindly give a thought in this.
I've a requirement to pass the bluetooth socket from one activity to the other. But I don't know how to do that. Kindly share some sample code if you have any.
Thanks
Sathish
Hi prasantha,
ReplyDeleteIs it possible to parcel a date and Map> if possible please let me know
thank u
ReplyDeleteHi Prasantha,
ReplyDeleteThis example is really good.
thanks.
I found this article very useful and hope that it will be very helpful for those who are new to Android.
ReplyDeleteHere I would like to ask one question that is it necessary to maintain order while UN-marshaling data i.e, one has to read the data in the same order in which the data has written to the parcel ?
Thanks man! I like the way you explain it and sahre your emotions with us!
ReplyDeletebest rgrads from Brazil!
Thanks for sharing this knowledge.
ReplyDeleteThanks man :)
ReplyDeleteGood Article !!!...Post more dude!!
ReplyDelete很有用,thanks
ReplyDeletethanks,good article
ReplyDeletehow to move multiple objects within two activities?
ReplyDeletehow to move multiple objects within two activities?
ReplyDeleteParcelable doesn't seem to work for a little more complicated object, e.g. a Parcelable with recursive call of its ownself, that means a Parcelable has a ListArray of dynamical size inside, e.g:
ReplyDeletepublic class ParcelData implements Parcelable {
int id;
String name;
String desc;
String[] cities = {"suwon", "delhi"};
ListArray mSubItemList;
}
and by calling
private ParcelData( Parcel in ) {
id = in.readInt();
name = in.readString();
desc = in.readString();
in.readStringArray(cities);
// now the problem, note: the dim info has already been written into Parcel
// by using writeToParcel()
int numberOfSubitems = in.readInt();
if( numberOfSubitems > 0 ) {
mSubItemList = new ListArry();
for( int i = 0; i < numberOfSubitems; i++ ) {
mSubItemList.add( new ParcelData(in) );
}
}
else {
mSubItemList = null;
}
// it causes exception, where is the problem???
}
Steven
Thanks for the code!
ReplyDeleteHello,
ReplyDeleteI want to get the location reminder whenever we are going to one place to another place when it reach that destination alert dialog is display in background using service.
Thanks much!
ReplyDeleteHello sir..:)
ReplyDeletePrateek here.
Nice example.
Thanks!! really great and easy to follow and understand example! really helped in my android uni proj!
ReplyDeletePrasanna and other folks who benefited out of this,
ReplyDeleteCan you please share the source code as an android project.
Thanks in advance.
Thanks it works
ReplyDeleteTG
Great job Prasanta !!! Many many thanks !!!
ReplyDeleteThanks
ReplyDeleteGreat job! But I only change
ReplyDeletepublic static final Parcelable.Creator CREATOR = new Creator() {
public ParcelData createFromParcel(Parcel source) {
return new ParcelData(source);
}
public ParcelData[] newArray(int size) {
return new ParcelData[size];
}
};
Good example!
ReplyDeleteThank so much
Nice tutorial. Thanks!
ReplyDeleteNice tutorial but why there is no real data placed in to Parcel? How to set data id, name... for each of element in Parcel list?
ReplyDeleteNice tutorial! Thank you very much!
ReplyDeleteGood post... very helpful for beginners like me.
ReplyDeleteAs already said in one of the replies, I had to change the CREATOR to parcel it successfully.
What about circular references ?I think parcelable does not support circular references
ReplyDeleteThanks for the helpful tutorial.
ReplyDeleteThanks a lot
ReplyDelete