Monday, September 3, 2012

Passing data between activities

One of the most important aspect in developing android application is how to pass data between activities. Usually an Android app is made by several activities that work together. These activities are pieces of code independent each other and we need to exchange information between them.

There are several strategies that can be applied to achieve this aim:

  • Shared Preferences
  • Database
  • Static class
  • Intents
The first two options are valid when we need to pass data and at the same time make this information persistent. This is the case of configuration parameter for example where we have to persist this information to not ask again it. We will cover this topic in another post, by now we are more interested on sharing data between activities without making them persistent. So we are interested on last two options.
Android exchange data

Static class

This is the easiest way to achieve our goal. Exploiting the Android feature that an app runs in a single process we can use a static class to exchange data between activities. In this case we can create several static method to hold the data we want to share.
Otherwise, we can use the singleton pattern that ensures we have only one instance of this class in all our JVM. In this case we create several method to hold the data.

Intents

This method is the most elegant one because it uses all the android features. Intent in android is an action description.For more information look here.
Intent supports three ways to pass data:
  • Direct: put our data into intents directly
  • Bundle: create a bundle and set the data here
  • Parcelable: It is a way of “serializing” our object.
To analyse these methods let’s suppose we have two activities: one that allows user to enter data (EditActivity) and the other one that shows to the user the data (ViewActivity). We have to pass this data between our activities. Let’s suppose, moreover, that we want to pass the name, surname and the email.

Direct

Intent has several method called putExtra(String name, …..) that allows us to save inside the Intent our information. Reading the API Doc we know that we can add string, longs, CharSequence, int and so on.It behaves like a Map where there’s the key and the value. In the caller (EditActivity) we can pass data in this way:

Intent i = new Intent(EditActivity.this, ViewActivity.class);
i.putExtra("name", edtName.getText().toString();
i.putExtra("surname", edtSurname.getText().toString();
i.putExtra("email", edtEmail.getText().toString();
startActivity(i);
Where “name”, “surname” and “email” are the keys. In other word first we create the intent (line 1) defining the caller activity (EditActivity) and the destination activity (ViewActivity), then we use putExtra to add our data. In the destination activity to retrieve the data sent we have:
protected void onCreate(Bundle savedInstanceState) {    
Intent i = getIntent();

String name = i.getStringExtra("name"));
String surname = i.getStringExtra("surname"));
String email = i.getStringExtra("email"));
. . .
}

As we can see this is very easy way to pass data and can be used when we have primitives or very simple object to share.

Bundle

Android has a class called Bundlewhere we can store our data and supports several data types like strings, chars, boolean, integer and so on.
Instead of using the Intent,as data container, we store our info directly into the bundle and then we save the bundle into the Intent. This approach is similar to the one described above.
In this case in the caller activity we have:
Intent i = new Intent(EditActivity.this, ViewActivity.class);
Bundle b = new Bundle();
b.putString("name", edtName.getText().toString());
b.putString("surname", edtSurname.getText().toString());
b.putString("email", edtEmail.getText().toString());
i.putExtra("personBdl", b);

startActivity(i);

As you can notice, we don’t store our data into the Intent but into the Bundle, while in the destination activity:

Intent i = getIntent();
Bundle b = i.getBundleExtra("personBdl");
String name = b.getString("name");
String surname = b.getString("surname");
String email = b.getString("email");

Parcelable

This is the most elegant way to pass data between activities and exploit all the android power. The “parcelable” operation is like serialization in Java, but while the java serialization in android is inefficient the “parcelable” operation is much more faster.
Parcelable in android is an interface and every object that wants to be passed across different activities using intent has to implement this interface. It is something like Serializable in Java. This interface has two method that we have to implements: describeContent() that returns an int and writeToParcel(Parcel dest, int flags) that returns a void.
More over a class that implements this interface must have a static field called CREATOR that is used by the OS to recreate the object.
This strategy is very useful when we need to pass complex objects and of course we can’t use the first two strategies. Let’s suppose we have a class called Person that contains three attributes:name, surname and email.

 
public class Person {
private String name;
private String surname;
private String email;
// get and set method

}
Now if we want to pass this class it must implement the Parcelable interface like that:
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];
}
};

Let’s analyze the code shown above. The first thing we did is to declare that our class implements Parcelable, so we have to override two method as stated above. The first one is describeContents() where we simply return the hashcode of our class. The second is writeToParcel. In this method we write the attribute values into the Parcel class. We use the Parcel methods to store our information. The order used to write them isn’t important, but we have to use the same order when we have to read it.

Once we have declared that our class is Parcelable, we have to implement a static field called CREATOR. This field is used by OS to “unparcel” or “deserialize” our class. This static field  looks like that

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];
}

};

There are two other methods to override the most important one is createFromParcel where we receive a parcel and we have to build up our Object, in our case Person. We call in this method a constructor, we made, that read data from the Parcel object:

// We reconstruct the object reading from the Parcel data
public Person(Parcel p) {
name = p.readString();
surname = p.readString();
email = p.readString();
}


It is import to notice that the order used to read data is the same used to write them.
Now we simply pass data like that:

Intent i = new Intent(EditActivity.this, ViewActivity.class);
Person p = new Person();
p.setName(edtName.getText().toString());
p.setSurname(edtSurname.getText().toString());
p.setEmail(edtEmail.getText().toString());
i.putExtra("myPers", p);
startActivity(i);
As you notice we simply put our object Person into the Intent. When we receive the data we have:

Bundle b = i.getExtras();
Person p = (Person) b.getParcelable("myPers");
String name = p.getName();
String surname = p.getSurname();
String email = p.getEmail();
The post Android parcelable tutorial: List and inner class is an advanced tutorial describing in-depth concepts about parceling List of object and inner class.

Passing data between activities Rating: 4.5 Diposkan Oleh: Unknown

0 comments:

Post a Comment