0

I have a Fragment MainFragment and I do:

Intent i = new Intent(getActivity(), PersonActivity.class);
startActivityForResult(i, 0);

The activity starts ok and it starts its own PersonFragment and inside the PersonFragment I do:

@Override
 public void onDestroy() {
      super.onDestroy();
      Intent i = new Intent();
      i.putExtra(PERSON_ID_EXTRA, getPersonId());
      i.putParcelableArrayListExtra(PERSON_CONTACT_LIST, (ArrayList<? extends Parcelable>) contactFriends);
      getActivity().setResult(Activity.RESULT_OK, i);
}

Back in my MainFragment I do:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if ( requestCode != 0) {
            return;
        }
        int personId = data.getIntExtra(PERSON_ID_EXTRA, -1);
        List<Person> contacts = data.getParcelableArrayListExtra(PERSON_CONTACT_LIST);
        for(Person p:contacts) {
            Log.d("APP", p.getFullName());
        }
}

I see that the code goes to onActivityResult but the data is null. What am I messing up here?

Update:
I see that pressing back button does not call onDestroy().
But where am all examples I saw used getActivity.finish() and I don't want to finish the activity. Only when the user presses e.g. back send the data

Update2:
I added the following and I go through that code but the Intent data in the result onActivityResult is still null

@Override
 public void onPause() {
      super.onPause();
      Intent i = new Intent();
      i.putExtra(PERSON_ID_EXTRA, getPersonId());
      i.putParcelableArrayListExtra(PERSON_CONTACT_LIST, (ArrayList<? extends Parcelable>) contactFriends);
      getActivity().setResult(Activity.RESULT_OK, i);
}
Jim
  • 18,826
  • 34
  • 135
  • 254
  • override `onKeyDown` instead of using `onDestroy()` – Apurva Mar 23 '15 at 16:14
  • @Apurva:I will try that but also please check update in OP – Jim Mar 23 '15 at 16:19
  • @Apurva:`onKeyDown` is activity method. I am setting the result in the fragment. How am I supposed to use it? – Jim Mar 23 '15 at 16:22
  • I also know that but I saw this http://stackoverflow.com/questions/22552653/how-to-implement-onbackpressed-intents-in-fragment – Apurva Mar 23 '15 at 16:23
  • If you want to use the startActivityForResult in your fragment don't forget to put a return false in your startActivityForResult in your FragmentActivity class. This one is prior to the fragment one. Hope that's helps – vincent091 Mar 23 '15 at 16:34
  • @vincent091:Which activity are you talking about? The hosting activity of the fragment that startActivityForResult or the hosting activity of the fragment that is being started? – Jim Mar 23 '15 at 16:38
  • @Jim Are you getting resultCode as RESULT_CANCELED? – Arun Kumar Mar 23 '15 at 16:45
  • @ArunKumar:I see in the debugger `0,0,null` as the arguments passed to `onActivityResult`. So yes – Jim Mar 23 '15 at 16:46
  • @ArunKumar:Why does this happen? – Jim Mar 23 '15 at 16:50

1 Answers1

2

From the Activity documentation about finish:

Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult().

From the documentation about onActivityResult:

Called when an activity you launched exits, giving you the requestCode you started it with, the resultCode it returned, and any additional data from it.

So, onActivityResult will only be called when the second activity finishes.

If you don't want to finish your PersonActivity to send the result to your main activity, then you may want to start another intent to send the data or pass the data using static fields (not a best practice at all).

In your case, to set your result when you press the back button, you can write a code like this:

public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            Intent i = new Intent();
            i.putExtra(PERSON_ID_EXTRA, getPersonId());
            i.putParcelableArrayListExtra(PERSON_CONTACT_LIST, (ArrayList<? extends Parcelable>) contactFriends);
            getActivity().setResult(Activity.RESULT_OK, i);
            finish();
            return true;
    }
    return false;
}

Follow up based on the comments:

The code for the finish() on the Activity class looks as follows:

// Call this when your activity is done
// and should be closed. The ActivityResult
// is propagated back to whoever launched
// you via onActivityResult().
public void finish() {
    if (mParent == null) {
        int resultCode;
        Intent resultData;
        synchronized (this) {
            resultCode = mResultCode;
            resultData = mResultData;
        }
        if (false) Log.v(TAG, "Finishing self: token=" + mToken);
        try {
            if (resultData != null) {
                resultData.prepareToLeaveProcess();
            }
            if (ActivityManagerNative.getDefault()
                .finishActivity(mToken, resultCode, resultData)) {
                mFinished = true;
            }
        } catch (RemoteException e) {
            // Empty
        }
    } else {
        mParent.finishFromChild(this);
    }
}

Here you can see that is the responsibility for setting the result values lays on the finish() method.

Then, before the Activity is destroyed, the onDestroy() method is called. That is the reason why setting the result of the Activity on the onDestroy() method won't work.

antonio
  • 18,044
  • 4
  • 45
  • 61
  • `start another intent to send the data`: What do you mean by this? – Jim Mar 23 '15 at 16:33
  • `So, onActivityResult will only be called when the second activity finishes.` But I see that it is called after `onPause` as well – Jim Mar 23 '15 at 16:34
  • @Jim I mean that you can create a `new Intent`, and start it with extras to send the data – antonio Mar 23 '15 at 16:37
  • @Jim I have made a test and in my case `onActivityResult` is not called after `onPause`. I will make another quick test to double check – antonio Mar 23 '15 at 16:38
  • But don't I create the a new Intent already? I am sorry, I am not sure what you mean – Jim Mar 23 '15 at 16:39
  • I press the back button and the `onActivityResult` is called. Where am I supposed to add the code `getActivity().setResult()`? – Jim Mar 23 '15 at 16:41
  • @Jim You can add your `setResult()` in an event (pressing a `Button`, onKeyDown, ...) but after that, and according to the documentation you should call `finish()`. In your case if you want to set your result when the back button is pressed you would need to do it on the `onKeyDown`. I will update my answer to show the code – antonio Mar 23 '15 at 16:50
  • But the method `onActivityResult` is called without calling `finish()`, it is just that the `Intent data` is `null` and the status is `CANCELLED` – Jim Mar 23 '15 at 16:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73600/discussion-between-antonio-and-jim). – antonio Mar 23 '15 at 16:55
  • By the way, I should put that snippet in onPause and onDestroy? – Jim Mar 23 '15 at 17:36
  • @Jim no, onKeyDown is a función of Activity. onPause and onDestroy will not call finish and hence will not set your result unless you explicitly call finish before – antonio Mar 23 '15 at 17:50
  • Does it make sense to override `onPause` and `onDestroy` to call `finish()` there to get the result? – Jim Mar 23 '15 at 18:00
  • @Jim no, when you call finish the activity finishes and then onDestroy is called, but the result is set first, so if you call finish and set your result on the onDestroy you will get an empty result – antonio Mar 23 '15 at 18:31