setResult ne fonctionne pas lorsque vous appuyez sur le bouton RETOUR

111

J'essaie de définir le résultat après avoir appuyé sur le bouton RETOUR. J'appelle surDestroy

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

Mais quand il s'agit de

onActivityResult(int requestCode, int resultCode, Intent data) 

le resultCode est 0 (RESULT_CANCELED) et les données sont «nulles».

Alors, comment puis-je transmettre le résultat de l'activité terminée par le bouton RETOUR?

alex2k8
la source

Réponses:

159

Vous devez remplacer la onBackPressed()méthode et définir le résultat avant l'appel à superclass, c'est-à-dire

@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();
}
n224576
la source
23
Notez que si vous utilisez cette approche, l'invocation de super.onBackPressed () doit se produire après l'appel à setResult () comme indiqué ci-dessus ou vous aurez à nouveau le problème d'origine!
jengelsma
1
C'est la meilleure réponse ici. Si nous surchargons onPause () ou onDestroy (), onBackPressed () sera appelé en premier et il mettra le résultat à 0. Soyez conscient de cela!
Marek
ou vous pouvez définir le résultat par défaut dans onCreate. N'importe quel endroit avant la fin () convient.
Helin Wang du
5
J'ai mis en œuvre une approche similaire mais cela ne fonctionne toujours pas. Pour l'instance, j'ai le code de requête et l'intention qui fonctionnent, mais le resultCode est toujours 0.
Neon Warge
68

Activityresult doit être défini avant d' finish() être appelé. Le fait de cliquer sur RETOUR appelle réellement finish()votre activity, vous pouvez donc utiliser l'extrait suivant:

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

    super.finish();
}

Si vous appelez NavUtils.navigateUpFromSameTask();dans onOptionsItemSelected(), finish()est appelé, mais vous obtiendrez le mal result code. Donc , vous devez appeler finish()pas navigateUpFromSameTaskdans onOptionsItemSelected(). mauvaise requestCode dans onActivityResult

JBM
la source
Cela fonctionne dans le cas des OP, mais pas en général, non? Il existe plus de méthodes que finish () qui induisent la fin du cycle de vie de l'application (via onPause () et onDestroy ())? Voir également mon commentaire à l'autre réponse.
pjv
Et même s'il n'y en avait pas, vous ne le sauriez pas quand il serait introduit dans une mise à jour d'API. Pas aussi facilement que vous le feriez lorsque le comportement de onPause () ou onDestroy () a changé. Ce sont les méthodes que vous êtes censé contourner.
pjv
6
@pjv - Je ne comprends pas votre point, qu'est-ce qui finisha à voir avec onPauseet onDestroy? Celles-ci ne sont absolument pas liées, sauf que cela finishdémarre le processus de résiliation dont onPauseet onDestroyfont partie.
JBM
20

Si vous souhaitez définir une coutume RESULT_CODEen onBackPressedcas alors vous devez d' abord définir le resultpuis appelez super.onBackPressed()et vous recevrez le même RESULT_CODEdans l'activité de l' appelant onActivityResultla méthode

    @Override
    public void onBackPressed()
    {
         setResult(SOME_INTEGER);
         super.onBackPressed();
    }
Khurram Shehzad
la source
10

J'ai refactoré mon code. Dans un premier temps, je préparais des données et définir comme activity resultdans onDestroy(cela ne fonctionne pas). Maintenant, je définis des activitydonnées chaque fois que les données à renvoyer sont mises à jour et je n'ai rien dedans onDestroy.

alex2k8
la source
Cela ne fonctionne pas pour moi puisque mes données sont mises à jour dans "onPause"
Bostone
Si votre activité est recréée après votre appel setResult(), vos données seront perdues.
Jarett Millard
3

Vous devez remplacer onOptionsItemSelected comme ceci:

@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);
    }
}
mdolanci
la source
2

Reportez-vous à la documentation onActivityResult (int, int, Intent)

La solution consiste à vérifier le resultCode pour la valeur Activity.RESULT_CENCELED . Si oui, cela signifie que soit PRÉCÉDENT a été pressé, soit l'activité s'est bloquée. J'espère que ça marche pour vous, ça marche pour moi :).

Ankur
la source
C'est la solution exacte. Vous devez utiliser le code de résultat. Personne ne peut définir le résultat à part vous dans le code. Donc, si le résultat est un moyen non OK soit ses presses à dos ou Crashed ..
John
0

onDestroyest trop tard dans la chaîne - remplacez plutôt onPauseet isFinishing()vérifiez si votre activité est à la fin de son cycle de vie.

Roman Nurik
la source
1
Non, c'est trop tard aussi.
alex2k8
J'appelle cela un bogue: code.google.com/p/android/issues/detail?id=1671 . Dans les applications complexes, je pense que pour cette raison, il y a juste un comportement que vous ne pouvez pas programmer.
pjv
C'est également très contre-intuitif. A tel point que je continue à faire la même erreur, depuis 2 ans déjà.
pjv
En fait, c'est encore pire. Et il existe dans JB pendant que je codifie. Si j'appelle setResult à partir de onPause, il est exécuté mais ni resultCode ni données ne sont définis lorsque onActivityReturn est exécuté. Pourquoi?
Bostone
Et c'est pourquoi: "Les implémentations de cette méthode (onPause) doivent être très rapides car la prochaine activité ne sera pas reprise tant que cette méthode ne retournera pas" goo.gl/8S2Y
Bostone
0

Essayez de remplacer onBackPressed (à partir du niveau Android 5), ou remplacez onKeyDown () et attrapez KeyEvent.BUTTON_BACK (voir Résultats d'activité Android ) Cela fait l'affaire pour moi.

MrJre
la source
0

Ne vous fiez à aucune logique exécutée dans onPause d'une activité lorsque vous revenez à la première. Selon la documentation:

Les implémentations de cette méthode (onPause) doivent être très rapides car la prochaine activité ne sera pas reprise jusqu'à ce que cette méthode retourne

Voir http://goo.gl/8S2Y pour plus de détails.

Le moyen le plus sûr est de définir le résultat une fois que chaque opération de modification de résultat est terminée (comme vous le mentionnez dans votre réponse)

Bostone
la source
0

Je colle la réponse peut être utile à d'autres personnes: quand un launcheMode réglé avec Android: launchMode = "singleTask" je ne peux pas non plus obtenir le résultat, le doc dit:

     /* <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.
 */

et:

     /* <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. 
 */
banxi1988
la source