Android Parcel data inside and between Activities


Aside your first Android project, every time you need to manage objects inside your application (like passing datas between Activities or restore the state of an Activity/Fragment) you need to create “custom” data and pass those objets between components.
The common case is when, for example, your activity contains a list of objects (like Books) and the user taps on a single object to see the details…so you need to pass this entry from one activity to another.

There is more: your activity is displaying the list of objects, user returns to the home and then after several hours comes back to your application, meanwhile Android system has decided to freeze your application because needs more resources and then after user is back to the application…what happens? your activity now is empty! the list of objects is gone.

So you need to repopulate the activity with the previous state after the user has returned to the application. Same problem if your activity supports both portrait and landscape orientation, when user rotates the device you must preserve the state of your activity.
NB: another option is to save data inside a local database but this tutorial wants to explain how to use Parcelable so no database for this time.
To pass datas between activities and for save/restore it during the life cycle of an Activity/Fragment, your objects must implement Parcelable.
You can think to Parcelable as the Android version of Serializable, keeping in mind that if you want, you can still use Serializable but you’ll lose some optimizations provided by Android…so I suggest you to use Parcelable and not Serializable.

Tip: How can you test the situation described before? obviously you can’t launch your application, return to the home then wait hours and come back! In this case you can simulate this behaviour using the DDMS view of Android:

Opening DDMS, on the left you can see the list of devices currently connected to your computer and all the processes attached, if you select one of this process you can stop that process with the “stop” red button, don’t forget to return to home or switch to another application before stops the process.
The main goal to make objects to implement Parcelable is that you can attach object (and list of objects) to Bundle that you use normally for passing and retrieving data between activities just like any other base Java types:

Bundle bundle = new Bundle();
bundle.putString(“Hello”,”World”);

Book book = new Book(1,”My first book”);

bundle.putParcelable(“book”,book);

And when you want to retrieve objects from the bundle:

Bundle bundle = getIntent().getExtras();
String hello = bundle.getString(“Hello”); // → World
Book book = bundle.getParcelable(“book”);

How to do that? Let’s start with the basic implementation of Book:

public class Book {
public long id;
public String title;
  public Book(long id, String title){
this.id = id;
this.title = title;
}
}

and let Book implements Parcelable:

public class Book implements Parcelable{

After that, Android Studio will complain about missing methods:

@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}

The first one is used if you need to put FileDescriptor inside the parcel, base implementation simply returns 0.

The second instead is used to create the Parcel object with the Book object, this is your chance to fill the Parcel with your data:

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(title);
dest.writeString(subtitle);
}

Well this is not enough because how can Android recreate your object starting with a Parcel? with writeToParcel you are saying ‘hey Android can you save to the Parcel the properties of that object?’ but you need also read from that Parcel.
For that you must tell to Android how to create your objects:

public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
public Book createFromParcel(Parcel source) {
return new Book(source);
}
  @Override
public Book[] newArray(int size) {
return new Book[size];
}
}

This code basically means that you are telling Android how to create a single object, and array of objects, of type Book object from a Parcel.
The important part is ‘new Book(source)’ that forces you to create a Book object with a Parcel that Android supplies to you:

public Book(Parcel in){
id = in.readLong();
title = in.readString();
subtitle = in.readString();
}

And here we are! Note that the order it’s very important: you must use the same order of method writeToParcel, so id/title/subtitle… if you try to read from the Parcel with id/subtitle/title you will end with title and subtitle properties of the book other way around.

After that books now are implementing Parcelable, saving a book to Bundle don’t complains anymore as an invalid action and so you can save and restore books inside your activity:

ArrayList<Book> books;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parcelable_example);
list = (ListView) findViewById(R.id.list);

if (savedInstanceState == null){
books = new ArrayList<Book>();
// populate books from remote server or local json
}else{
books = savedInstanceState.getParcelableArrayList(“books”);
}
  adapter = new BookAdapter(this, books);
list.setAdapter(adapter);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(“books”, books);
}

Tips:
If you have want to save/retrieve a boolean inside a Parcel, you may notice that there is no support for it, for this value you should use this code:

dest.writeByte((byte) (bool ? 1 : 0)); ← writing
this.bool = in.readByte() == 1; ← reading

Useful links:
http://developer.android.com/reference/android/os/Parcelable.html

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.