3 Comments

Sending Data Between Activities in Android

Android Intents are objects used to trigger actions from other Android Activities. One of the most common uses of Intents is to open a new Activity in your app. Often, you will want to pass information to the new Activity. In this post, I’ll discuss a few ways to pass data between Activities using Intents, including passing primitives, Strings, and object types.

Intent Extras

Intent objects all have an extras property. This is a Bundle, storing key value pairs in which keys are Strings. It’s the same structure you see every time you override an Activity’s onCreate method. The bundle is one of the mechanisms through which Intents transfer data to other activities, and it is my main focus in this post.

Primitives, Strings, and Arrays

Primitives and Strings can easily be put into Intents. For example, the following code will store an int variable called intToSend in an Intent, giving the int the key “my-int.”


Intent intent = new Intent(this, NextActivity.class);
int intToSend = 42;

intent.putExtra("my-int", intToSend);

You can do the same with other primitive types, Strings, or arrays of primitives or Strings.

At this point, you can signal that we intend to start a new Activity that will receive the Intent we just made, as you normally would with:


startActivity(intent);

A quick digression: In case you didn’t realize this, putExtra returns the calling object. This means you can choose between writing code like the example above or chaining calls, like this:


startActivity(new Intent(this, NextActivity.class)
    .putExtra("my-string", "hello intent!")
    .putExtra("is-snowing", true));

Okay, so at this point, things are pretty simple. Now, let’s see what happens if you try to pass arbitrary objects using the Intents. Say we have a Computer class, and we have an instance called computer.

If you write:


intent.putExtra("my-computer", computer);

you should see an error; Bundles–and so Intents–can’t hold just any type of object. But if you need to pass objects between Activities, there is still hope!

Serializables

One way to pass objects in Intents is for the object’s class to implement Serializable. This interface doesn’t require you to implement any methods; simply adding implements Serializable should be enough. To get the object back from the Intent, just call intent.getSerializableExtra. You’ll probably want to cast the return value to the expected value type.

This is a very simple approach. Unfortunately, it can be slow.

Parcelable

Another approach to sending objects is to implement Android’s Parcelable interface. This interface requires three things: a public void writeToParcel method, a public int describeContents, and a non-static field called CREATOR that implements Parcelable.Creator. writeToParcel is responsible for serializing the data, and the Creator is responsible for deserializing it to reconstruct the original Parcelable object.

I’ve created a simple class called Sample to illustrate how this works. It has two data members: foo, and bar. Here’s what the code looks like:


public class Sample implements Parcelable {


    private int foo;
    
    private String bar;

    
    
    public Sample(int foo, String bar) {
        this.foo = foo;

        this.bar = bar;

    }

    
    
    protected Sample(Parcel in) {
        foo = in.readInt();
        bar = in.readString();
    }

    
    
    @Override
    
    public String toString() {
        return String.format("[Sample: %d, %s]", foo, bar);

    }

    
    
    public static final Creator CREATOR = new Creator() {

        @Override
        public Sample createFromParcel(Parcel in) {
            return new Sample(in);
        }

       
        
        @Override

        public Sample[] newArray(int size) {
            return new Sample[size];
        }
    
    };

    
    
    @Override
    
    public int describeContents() {
        
    	return 0;
   
    }

    
    
    @Override
    
    public void writeToParcel(Parcel parcel, int i) {
        
    	parcel.writeInt(foo);
        
    	parcel.writeString(bar);
    
    }

}

Breaking It Down

Let’s take a quick look at what’s going on. The writeToParcel method writes instance variables to its parcel argument. The protected constructor does just the opposite; it reads data from its argument, and stores it in instance variables. describeContents can be used to set bitwise flags indicating special data types. The Creator is used to take in an input Parcel to be deserialized. In this case, it calls the constructor, passing in the Parcel.

This is a lot of code for such a seemingly simple task. However, using Android Studio–and likely other IDEs if you choose–almost all of the code is written for you. In fact, the only part of the code above that I wrote myself is:


public class Sample implements Parcelable {

    
	private int foo;
    
	private String bar;

    
	
	public Sample(int foo, String bar) {
        
		this.foo = foo;
        
		this.bar = bar;
    
	}

}

One last point: Why would anyone use Parcelables when they take more work than Serializables? The main reason is that Parcelizables work much faster than Serializables. Experiments in this blog post show Parcelables to be 10 times faster in serializing objects than Serializables. The speed difference is due to Serializables using reflection to determine the serialization.

Well, that’s it for the basics of transferring data between Intents using extras. Happy data sending!