Sharing Data Between Activities

Intro

There are several ways to share data between Activites, each with their own pros and cons.  

This lesson will discuss the first two options.  We'll go over option three in detail in a future lesson.

Using Intents to pass data

In order to launch one activity from another, you must use an Intent object.  After instantiating a new Intent, you simply call the startActivity() method, passing the intent as an argument.  The OS will examine the included intent to determine which Activity on the device it should display.  On of the great features of Intents is the ability to bundle data with an intent object, which is in turn delivered to the launched Activity.  This data is called an Intent Extra.  

This example shows an Activity launching another activity called "NoResultActivity", and bundling with the Intent a String object (variable name colorString) with the key "color":

Intent intent = new Intent(this, NoResultActivity.class);
// adding extended data to intent using key/value pair
intent.putExtra("color", colorString);
startActivity(intent);

Once NoResultActivity runs, the Intent that was used to launch it can be retrieved in the onCreate method by calling getIntent().  Once you have the Intent that was used to launch an Activity, you can retrieve any extras that were bundled with it.  There are three ways to accomplish this.

Intent intent = getIntent();

// Option 1
String color = intent.getStringExtra("color");

// Option 2
Bundle extras = intent.getExtras();
String color = extras.getString("color");

// Option 3
String color = intent.getString("color", "fafafa");

In option 1, you retrieve the String directly.  In Option 2, you first instantiate a Bundle, which you then use to retrieve the String.  If you're only passing one item, then there's really no benefit to using one over the other.  But if you're passing more than one item, using option 2 may save you some code.  Also, option 2 allows you to use another version of the getString() method that lets you specify a default value if there is no item corresponding to the key you provided.  For example, in option 3 above, we first try to retrieve the String object with the key "color".  But if color doesn't exist, the value "fafafa" is used.

Using Your Own Bundle

But wait...that's not the only way to work with Extras!  By default, when you add extras to an intent, those values are put inside an unnamed Bundle object.  Instead of that, you can also create and use a Bundle object of your own creation to hold the Extras:

Intent intent = new Intent(this, NoResultActivity.class);
// using a Bundle Object to add data to intent
Bundle extras = new Bundle();
extras.putString("color", colorString);
intent.putExtras(extras);
startActivity(intent);

When using your own Bundle, all extras are added to your Bundle as before, and the putExtras() method is used to associate that Bundle with the Intent.  What happens behind the scenes is that the contents of your Bundle are then copied into the Intent's default Bundle, which means that a slight (insignificant?) amount of extra overhead is needed.  So why would you want to use your own Bundle?  Perhaps your Activity can launch several other activities that require the same Extras.  Using your own Bundle means tht you can reuse it for each Intent.

Using Intents to return data

At this point, we've only discussed one-way passing of data to an Activity when it's launched.  But sometimes it's necessary to return data back to the calling activity.  Enabling this functionality requires us to make a few changes to the way we launch an Activity.

In the starting Activity: 

  1. For starters, instead of calling the Activity using startActivity(), we need to use startActivityForResult().  
  2. A user-defined request code is also sent as an argument in the startActivityForResult() method.  This is what the calling Activity uses to keep track of intents and identify which called Activity is returning data.
  3. The calling Activity must override the onActivityResult method.  This is where the Activity will retrieve any data that was returned to it, using the request code to determine which Activity triggered it.

For example, to launch an Activity called ResultActivity:

int request_Code = 1775; // this should be a class variable
...
Intent intent = new Intent(this, ResultActivity.class);
startActivityForResult(intent, request_Code); // notice the extra argument

When the called Activity is destroyed, the onActivityResult method is triggerd in the calling Activity:

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    // check to see which activity is returning the result
    if (requestCode == request_Code) {
        // check result code
        if (resultCode == RESULT_OK) {​
            String response = intent.getStringExtra("anothercolor");
            mainDisplay.setText(response);
        }
    }
}
You should always check the returned request code with the request code value you specified.  The returned data can be retrieved from the intent just like before.  
 
In the launched Activity:

When the called Activity is finished and is ready to return data back to the Activity that launched it, i:

  1. creates a new Intent
  2. adds the data to be returned  (just like before)
  3. sets a result code in the Intent using setResult()
    1.  The result code can be on of the predefined Android codes (RESULT_CANCELEDRESULT_OKRESULT_FIRST_USER) or an integer value of your choosing.
  4. destroys itself using finish();
Intent intent = new Intent();
intent.putExtra("returned_color", "I really liked " + color);

// set the result code
setResult(Activity.RESULT_OK, intent);

// destroy the current activity
finish();

 

Using setData and getData

Finally, you have one more option when it comes to passing data.  Instead of using an Intent extra, you can use the setData() method;

Intent intent = new Intent();

// using setData() to send a value.  This is another way to add data to an intent!
intent.setData(Uri.parse("I really liked " + color));

To retrieve data that has been added to an Intent using setData, you use the getdata() method:

// get data set with setData()
String response = intent.getData().toString();

 

Download working code from GitHub: https://github.com/jonipepin/DataSharingExample