Passing data through Activities

Updated on Nov 29, 2016 - added information on EventBus sticky


Assume we have a simple POJO which contains multiple information

public class POJO  
{
    public int integer;
    public String string;
    public Boolean bool;
    public Float f;

    public POJO(int integer, String string, Boolean bool, Float f)
    {
        this.integer = integer;
        this.string = string;
        this.bool = bool;
        this.f = f;
    }

    // getters and setters
}

1. Normal intent

To pass data via an intent, use putExtra() in the intent.

Passing single variable to an activity, use this method.

Intent intent = new Intent(context, MyActivity.class);  
intent.putExtra("keyName","value");  
intent.putExtra("keyName2", 2);  
startActivity(intent);  

To retrieve this data in the next Activity,

String data = getIntent().getExtras().getString("keyName");  
int data2 = getIntent().getExtras().getInt("keyName2", 0);  

Alternatively, with null checking technique (recommended):

Bundle extras = getIntent().getExtras();  
if (extras != null) {  
    String value = extras.getString("keyName");
    int data2 = extras.getInt("keyName2", 0);
}

2. Using Serializable

Serializable is a standard Java interface. You simply mark a class Serializable by implementing the interface, and Java will automatically serialize it in certain situations 1. Serializable - close to zero boilerplate, but it is the slowest approach and also requires hard-coded strings when pulling values out the intent (non-strongly typed).2

Make our POJO class implements Serializable

public class POJO implements Serializable  
{
    public int integer;
    public String string;
    public Boolean bool;
    public Float f;

    public POJO(int integer, String string, Boolean bool, Float f)
    {
        this.integer = integer;
        this.string = string;
        this.bool = bool;
        this.f = f;
    }
}

Sending our POJO to another activity

Intent intent = new Intent(context, MyActivity.class);  
intent.putExtra("myPojoKey", new POJO(1, "2", true, 3.0f));  
startActivity(intent);  

Receiving our POJO intent

Bundle extras = getIntent().getExtras();  
if (extras != null) {  
    POJO pojoObject = extras.getSerializableExtra("myPojoKey");
}

3. Using Parcelable

Parcelable is an Android specific interface where you implement the serialization yourself. It was created to be far more efficient that Serializable, and to get around some problems with the default Java serialization scheme. 1

Parcelable - fast and Android standard, but it has lots of boilerplate code and requires hard-coded strings for reference when pulling values out the intent (non-strongly typed). 2

Make our POJO implements Parcelable

Protip: In Android Studio IDE, this class can easily created by generating the boilerplate code.

public class POJO implements Parcelable {  
    public int integer;
    public String string;
    public Boolean bool;
    public Float f;

    public POJO(int integer, String string, Boolean bool, Float f) {
        this.integer = integer;
        this.string = string;
        this.bool = bool;
        this.f = f;
    }

    //used to deflate the POJO
    //before sending to destination activity
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeStringArray(new String[] {
            String.valueOf(this.integer),
            this.string,
            String.valueOf(this.bool),
            String.valueOf(this.f)
        });
    }

    //used to inflate the POJO once it has
    //reached its destination activity
    public POJO(Parcel in) {
        String[] data = new String[4];
        in.readStringArray(data);
        this.integer = Integer.parseInt(data[0]);
        this.string = data[1];
        this.bool = Boolean.parseBoolean(data[2]);
        this.f = Float.parseFloat(data[3]);
    }

    //method on the interface
    @Override
    public int describeContents() {
        return 0;
    }

    //More boilerplate
    //Failure to add this results in the following exception
    //"android.os.BadParcelableException: Parcelable protocol 
    //requires a Parcelable.Creator object called  CREATOR on class"
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public POJO createFromParcel(Parcel in) {
            return new POJO(in); 
        }

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

Sending our POJO to another activity

Similarly,

Intent intent = new Intent(context, MyActivity.class);  
intent.putExtra("myPojoKey", new POJO(1, "2", true, 3.0f));  
startActivity(intent);  

Receiving our POJO intent

Bundle extras = getIntent().getExtras();  
if (extras != null) {  
    POJO pojoObject = extras.getParcelableExtra("myPojoKey"); 
}

4. Using EventBus

Event Bus - zero boilerplate, fastest approach, and does not require hard-coded strings, but it does require an additional dependency (although usually lightweight, ~40 KB). 2

More detailed explanation: http://www.andreas-schrade.de/2015/11/28/android-how-to-use-the-greenrobot-eventbus/

Creating our bus

Simply call this method in any line of your code to receive EventBus instance.

EventBus myEventBus = EventBus.getDefault();  

Creating our event

Guess what, our POJO is our event.

We need to create a new model-like class to pass our event to a subscriber.

public class POJOEvent {  
    POJO pojo;

    public POJOEvent(POJO pojo) {
        this.pojo = pojo;
    }

    // getters and setters
}

Creating our sender

Sending data on the bus is as easy as fuck.

POJO myPojo = new POJO(1, "2", true, 3.0f);  
EventBus.getDefault().post(new POJOEvent(myPojo));  

Creating our subscriber (retriever)

1. Register the bus

Register inside onCreate(), onStart(), or onResume().

EventBus.getDefault().register(this); // this == your class instance  

2. Unregister the bus

Read on why we need to unregister an instance: http://stackoverflow.com/a/31931742/996701

Unregister should happen inside onDestroy(), onPause() or onStop().

EventBus.getDefault().unregister(this);  

3. Retrieving the event

// This method will be called when a POJO event is posted
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(POJOEvent event){  
  // your implementation
  processEvent(event.getPojo());
}

Sticky Event

Some events carry information that is of interest after the event is posted.3

My personal use-case would be, how to replace setIntent or avoiding our model class to implement Parcelable/Serializable. Whenever I want to pass a model class, EventBus can do this for you.

The process is similar like the above, only thing we have to do is to change .post() to .postSticky(), and in our subscriber method we would want to explicitly define that it is a sticky event.

Posting a sticky event:

EventBus.getDefault().postSticky(new POJOEvent(myPojo));  

Subscribing a sticky event:

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(POJOEvent event){  
  processEvent(event.getPojo());
}

Resources

  1. http://stackoverflow.com/a/3323554/996701
  2. http://stackoverflow.com/a/20056245/996701
  3. http://greenrobot.org/eventbus/documentation/configuration/sticky-events/

Aiman Baharum

More about this blog https://github.com/aimanbaharum/random-wiki/wiki

Kuala Lumpur, Malaysia http://www.aimanbaharum.com

Subscribe to Knowledge Log

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!