Sending data back to the Main Activity in Android

Viewed 346268

I have two activities: main activity and child activity.
When I press a button in the main activity, the child activity is launched.

Now I want to send some data back to the main screen. I used the Bundle class, but it is not working. It throws some runtime exceptions.

Is there any solution for this?

13 Answers

There are a couple of ways to achieve what you want, depending on the circumstances.

The most common scenario (which is what yours sounds like) is when a child Activity is used to get user input - such as choosing a contact from a list or entering data in a dialog box. In this case, you should use startActivityForResult to launch your child Activity.

This provides a pipeline for sending data back to the main Activity using setResult. The setResult method takes an int result value and an Intent that is passed back to the calling Activity.

Intent resultIntent = new Intent();
// TODO Add extras or a data URI to this intent as appropriate.
resultIntent.putExtra("some_key", "String data"); 
setResult(Activity.RESULT_OK, resultIntent);
finish();

To access the returned data in the calling Activity override onActivityResult. The requestCode corresponds to the integer passed in the startActivityForResult call, while the resultCode and data Intent are returned from the child Activity.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  switch(requestCode) {
    case (MY_CHILD_ACTIVITY) : {
      if (resultCode == Activity.RESULT_OK) {
        // TODO Extract the data returned from the child Activity.
        String returnValue = data.getStringExtra("some_key");
      }
      break;
    } 
  }
}

UPDATE Mar. 2021

As in Activity v1.2.0 and Fragment v1.3.0, the new Activity Result APIs have been introduced.

The Activity Result APIs provide components for registering for a result, launching the result, and handling the result once it is dispatched by the system.

So there is no need of using startActivityForResult and onActivityResult anymore.

In order to use the new API, you need to create an ActivityResultLauncher in your origin Activity, specifying the callback that will be run when the destination Activity finishes and returns the desired data:

private val intentLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->

        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.getStringExtra("key1")
            result.data?.getStringExtra("key2")
            result.data?.getStringExtra("key3")
        }
    }

and then, launching your intent whenever you need to:

intentLauncher.launch(Intent(this, YourActivity::class.java))

And to return data from the destination Activity, you just have to add an intent with the values to return to the setResult() method:

val data = Intent()
data.putExtra("key1", "value1")
data.putExtra("key2", "value2")
data.putExtra("key3", "value3")

setResult(Activity.RESULT_OK, data)
finish()

For any additional information, please refer to Android Documentation

All these answers are explaining the scenario of your second activity needs to be finish after sending the data.

But in case if you don't want to finish the second activity and want to send the data back in to first then for that you can use BroadCastReceiver.

In Second Activity -

Intent intent = new Intent("data");
intent.putExtra("some_data", true);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

In First Activity-

private BroadcastReceiver tempReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // do some action
    }
};

Register the receiver in onCreate()-

 LocalBroadcastManager.getInstance(this).registerReceiver(tempReceiver,new IntentFilter("data"));

Unregister it in onDestroy()

Another way of achieving the desired result which may be better depending on your situation is to create a listener interface.

By making the parent activity listen to an interface that get triggered by the child activity while passing the required data as a parameter can create a similar set of circumstance

Just a small detail that I think is missing in above answers.

If your child activity can be opened from multiple parent activities then you can check if you need to do setResult or not, based on if your activity was opened by startActivity or startActivityForResult. You can achieve this by using getCallingActivity(). More info here.

Related