112
votes

I am trying to setResult after the BACK button was pressed. I call in onDestroy

Intent data = new Intent();
setResult(RESULT_OK, data) 

But when it comes to

onActivityResult(int requestCode, int resultCode, Intent data) 

the resultCode is 0 (RESULT_CANCELED) and data is 'null'.

So, how can I pass result from activity terminated by BACK button?

10

10 Answers

164
votes

You need to overide the onBackPressed() method and set the result before the call to superclass, i.e

@Override
public void onBackPressed() {
    Bundle bundle = new Bundle();
    bundle.putString(FIELD_A, mA.getText().toString());
    
    Intent mIntent = new Intent();
    mIntent.putExtras(bundle);
    setResult(RESULT_OK, mIntent);
    super.onBackPressed();
}
70
votes

Activity result must be set before finish() is called. Clicking BACK actually calls finish() on your activity, so you can use the following snippet:

@Override
public void finish() {
    Intent data = new Intent();
    setResult(RESULT_OK, data); 

    super.finish();
}

If you call NavUtils.navigateUpFromSameTask(); in onOptionsItemSelected(), finish() is called, but you will get the wrong result code. So you have to call finish() not navigateUpFromSameTask in onOptionsItemSelected(). wrong requestCode in onActivityResult

21
votes

If you want to set some custom RESULT_CODE in onBackPressed event then you need to first set the result and then call the super.onBackPressed() and you will receive the same RESULT_CODE in the caller activity's onActivityResult method

    @Override
    public void onBackPressed()
    {
         setResult(SOME_INTEGER);
         super.onBackPressed();
    }
10
votes

I refactored my code. Initially I prepared some data and set it as activity result in onDestroy (this did not work). Now I set activity data each time the data to be returned is updated, and have nothing in onDestroy.

4
votes

You should override onOptionsItemSelected like this:

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        final Intent mIntent = new Intent();
        mIntent.putExtra("param", "value");
        setResult(RESULT_OK, mIntent);
        finish();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}
2
votes

Refer onActivityResult(int, int, Intent) doc

Solution is to check the resultCode for value Activity.RESULT_CENCELED. If yes, then it means that either BACK was pressed or the activity crashed. Hope it works for you guys, works for me :).

0
votes

onDestroy is too late in the chain — instead override onPause and check isFinishing() to check if your activity is at the end of its lifecycle.

0
votes

Try overriding onBackPressed (from android level 5 up), or override onKeyDown() and catch KeyEvent.BUTTON_BACK (see Android Activity Results) This does the trick for me.

0
votes

Don't rely on any logic executed in onPause of one activity when you return to the initial one. According to the docs:

Implementations of this method (onPause) must be very quick because the next activity will not be resumed until this method returns

See http://goo.gl/8S2Y for details.

The safest way is to set result after each result altering operation is complete (as you mention in your answer)

0
votes

i paste the answer may be will be helpful to other people: when a set launcheMode with android:launchMode="singleTask" i also cant get the result, the doc says:

     /* <p>Note that this method should only be used with Intent protocols
 * that are defined to return a result.  In other protocols (such as
 * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
 * not get the result when you expect.  For example, if the activity you
 * are launching uses the singleTask launch mode, it will not run in your
 * task and thus you will immediately receive a cancel result.
 */

and:

     /* <p>As a special case, if you call startActivityForResult() with a requestCode 
 * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
 * activity, then your window will not be displayed until a result is 
 * returned back from the started activity.  This is to avoid visible 
 * flickering when redirecting to another activity. 
 */