Thursday, June 17, 2010

Parcelable - How to do that in Android

Passing data between activities is quite easy. You would normally do that using the Bundle packed into an intent. But sometimes you need to pass complex objects from one activity to another. One workaround would be to keep a static instance of the object int your Activity and access it from you new Activity. This might help, but it's definitely not a good way to do this. To pass such objects directly through the Bundle, your class would need to implement the Parcelable interface.

For example you have a class called Student, which has three fields.
1. id
2. name
3. grade

You can create a POJO class for this, but you need to add some extra code to make it Parcelable. Have a look at the implementation.

   1: public class Student implements Parcelable{
   2:     private String id;
   3:     private String name;
   4:     private String grade;
   5:  
   6:     // Constructor
   7:     public Student(String id, String name, String grade){
   8:         this.id = id;
   9:         this.name = name;
  10:         this.grade = grade;
  11:     }
  12:     // Getter and setter methods
  13:     .........
  14:     .........
  15:     
  16:     // Parcelling part
  17:     public Student(Parcel in){
  18:         String[] data = new String[3];
  19:  
  20:         in.readStringArray(data);
  21:         this.id = data[0];
  22:         this.name = data[1];
  23:         this.grade = data[2];
  24:     }
  25:  
  26:     @override
  27:     public int describeContents(){
  28:         return 0;
  29:     }
  30:  
  31:     @Override
  32:     public void writeToParcel(Parcel dest, int flags) {
  33:         dest.writeStringArray(new String[] {this.id,
  34:                                             this.name,
  35:                                             this.grade});
  36:     }
  37:     public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
  38:         public Student createFromParcel(Parcel in) {
  39:             return new Student(in); 
  40:         }
  41:  
  42:         public Student[] newArray(int size) {
  43:             return new Student[size];
  44:         }
  45:     };
  46: }


Once you have created this class, you can easily pass objects of this class through the Intent like this, and recover this object in the target activity.

   1: intent.putExtra("student", new Student("1","Mike","6"));

Here, the student is the key which you would require to unparcel the data from the bundle.

   1: Bundle data = getIntent().getExtras();
   2: Student student = data.getParcelable("student");

This example shows only String types. But, you can parcel any kind of data you want. Try it out.

27 comments:

  1. Hey, good tip. But why don´t you just pass a Serializable as a parameter? So you can work with your original object.

    ReplyDelete
  2. Well, Serializable also helps, but it's too slow as compared to Parcelable. In Android parlance, I assume that your objects that you would need to pass between Activities would not be super complex.

    Implementation-wise, Serializable seems to be a lot simpler, but if you consider the performace, Parcelable wins here.

    ReplyDelete
  3. Nice article, in one shot developer would be able to understand Object Passing concept. Good One.

    ReplyDelete
  4. Very good article!

    Just on question. How will you proceed if one of the member is not a String (a Bitmap in my case).

    Using an array of Object and casting?

    ReplyDelete
  5. Parceable seems ok for trivial pojos but anything complex is going to require a lot of code to serialize/parcel and to deserialize/un-parcel. Perhaps it's easier to use GSON/JSON to pass the object around as a JSON string and to use Gson().fromJson() when one needs to turn it back into a Java object.

    ReplyDelete
  6. Can you please tell me how to pass a image from one activity to another activity with an example...

    ReplyDelete
  7. You should not be doing that. A better suggestion would be to pass the file path of the image as a string.

    ReplyDelete
  8. Thas's true. Path is better. But how I can figure out it? For example we have one more member in the class Student : Bitmap photo;
    What is path in this case?

    ReplyDelete
  9. Well, you can have the path or URL or the resource ID of the Bitmap that you have created.

    ReplyDelete
  10. How can you persist a Parceable (without Intents), just recreate the object once the App is started again?

    ReplyDelete
  11. That, or serialize it to a file. That should work although I haven't done that myself. Any specific reason of not using Intents??

    ReplyDelete
  12. tnks,i liked and its very help full code that you provided

    ReplyDelete
  13. How do you send a Student[] though?

    ReplyDelete
  14. http://developer.android.com/reference/android/content/Intent.html#putParcelableArrayListExtra%28java.lang.String,%20java.util.ArrayList%3C?%20extends%20android.os.Parcelable%3E%29

    ReplyDelete
  15. Each of my data classes has a bundle(Bundle b) and an unbundle(Bundle b) method. I guess this is sort of a do-it-yourself parcelling scheme?

    ReplyDelete
  16. Hi, you example is very clear but, I have a question:
    If the object change after I passed it as extra, what is the method to see this change on the activity?
    I try be more clear: I have a thread that update the value of an object started with the main activity. When the user request a new activity I pass as extra this object. Now I want to keep updated also the object on the new activity. What is the method to do this?
    Thanks in advance

    ReplyDelete
  17. @Simone: Check this, if it helps:
    http://developer.android.com/reference/android/app/Activity.html#onNewIntent%28android.content.Intent%29

    ReplyDelete
  18. Thanks for great article.
    Just want to ask you, if is Student(int,String,boolean,float) so how can we createFromParcel() and writeToParcel() ?

    ReplyDelete
  19. This comment has been removed by the author.

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. This comment has been removed by the author.

    ReplyDelete
  22. My class is more or less identical to your example. Why would I use parceling rather than just use get methods on the three attributes and save them to the savedInstanceState bundle?

    Am I overcomplicating things by using this for instance storage?
    My class is identical to the student class but I intend to store between 1-10 of them.

    ReplyDelete
  23. I want to pass whole list from one activity to another activity
    ListSongTitle from MappsActivity to player.java that is also an activty.

    So plz tell.and how i will get it there.!!

    send plzz at//" rahul.iec44@gmail.com"

    ReplyDelete
  24. This comment has been removed by the author.

    ReplyDelete
  25. @deco. Placing parcelable logic in you model class makes the code reusable. At any point you find yourself passing through an intent several or all of the data members of a given object, you should consider using parcelable.

    ReplyDelete