Afficher le DialogFragment de onActivityResult

J’ai le code suivant dans mon onActivityResult pour un fragment de la mienne:

onActivityResult(int requestCode, int resultCode, Intent data){ //other code ProgressFragment progFragment = new ProgressFragment(); progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG); // other code } 

Cependant, je reçois l’erreur suivante:

 Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 

Quelqu’un sait ce qui se passe ou comment je peux résoudre ce problème? Je dois noter que j’utilise le package de support Android.

Si vous utilisez la bibliothèque de support Android, la méthode onResume n’est pas l’endroit idéal pour jouer avec des fragments. Vous devriez le faire dans la méthode onResumeFragments, voir la description de la méthode onResume: http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onResume%28%29

Donc, le code correct de mon sharepoint vue devrait être:

 private boolean mShowDialog = false; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); // remember that dialog should be shown mShowDialog = true; } @Override protected void onResumeFragments() { super.onResumeFragments(); // play with fragments here if (mShowDialog) { mShowDialog = false; // Show only if is necessary, otherwise FragmentManager will take care if (getSupportFragmentManager().findFragmentByTag(PROG_DIALOG_TAG) == null) { new ProgressFragment().show(getSupportFragmentManager(), PROG_DIALOG_TAG); } } } 

EDIT: Pas un bug, mais plus d’une lacune dans le framework des fragments. La meilleure réponse à cette question est celle fournie par @Arcao ci-dessus.

—- Message original —-

En fait, c’est un bogue connu avec le package de support (edit: pas réellement un bogue. Voir le commentaire de @ alex-lockwood). Un travail posté dans les commentaires du rapport de bogue consiste à modifier la source du DialogFragment comme suit:

 public int show(FragmentTransaction transaction, Ssortingng tag) { return show(transaction, tag, false); } public int show(FragmentTransaction transaction, Ssortingng tag, boolean allowStateLoss) { transaction.add(this, tag); mRemoved = false; mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit(); return mBackStackId; } 

Notez que c’est un hack géant. La façon dont je l’ai fait était de créer mon propre fragment de dialog avec lequel je pouvais enregistrer à partir du fragment d’origine. Lorsque cet autre fragment de dialog faisait des choses (comme être rejeté), il disait à tous les auditeurs que cela disparaissait. Je l’ai fait comme ça:

 public static class PlayerPasswordFragment extends DialogFragment{ Player toJoin; EditText passwordEdit; Button okButton; PlayerListFragment playerListFragment = null; public void onCreate(Bundle icicle){ super.onCreate(icicle); toJoin = Player.unbundle(getArguments()); Log.d(TAG, "Player id in PasswordFragment: " + toJoin.getId()); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle){ View v = inflater.inflate(R.layout.player_password, container, false); passwordEdit = (EditText)v.findViewById(R.id.player_password_edit); okButton = (Button)v.findViewById(R.id.ok_button); okButton.setOnClickListener(new View.OnClickListener(){ public void onClick(View v){ passwordEntered(); } }); getDialog().setTitle(R.ssortingng.password_required); return v; } public void passwordEntered(){ //TODO handle if they didn't type anything in playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toSsortingng()); dismiss(); } public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){ this.playerListFragment = playerListFragment; } public void unregisterPasswordEnteredListener(){ this.playerListFragment = null; } } 

Alors maintenant, j’ai un moyen de notifier le PlayerListFragment quand les choses se passent. Notez qu’il est très important que vous appeliez unregisterPasswordEnteredListener de manière appropriée (dans le cas ci-dessus lorsque le PlayerListFragment “disparaît”), sinon ce fragment de dialog pourrait essayer d’appeler des fonctions sur le listener enregistré lorsque cet écouteur n’existe plus.

Le commentaire laissé par @Natix est un raccourci rapide que certaines personnes ont peut-être supprimé.

La solution la plus simple à ce problème consiste à appeler super.onActivityResult () AVANT d’exécuter votre propre code. Cela fonctionne indépendamment du fait que vous utilisiez ou non la bibliothèque de support et que vous mainteniez une cohérence comportementale dans votre activité.

Il y a:

  • Pas besoin d’ append de faux délais en utilisant des threads, des handlers ou des sleeps .
  • Pas besoin de commettre autorisant la perte d’état ou la sous-classe pour remplacer show (). Ce n’est pas un bug, c’est un avertissement. Ne jetez pas les données d’état. ( Un autre , exemple de bonus )
  • Pas besoin de suivre les fragments de dialog dans votre activité (bonjour les memory leaks!)
  • Et par Dieu, pas besoin de jouer avec le cycle de vie de l’activité en appelant onStart () manuellement .

Plus j’y lis, plus j’ai vu de piratage.

Si vous rencontrez toujours des problèmes, alors celui d’ Alex Lockwood est celui à vérifier.

  • Pas besoin d’ écrire du code pour onSaveInstanceState () ( un autre )

Android appelle onActivityResult() avant onStart() .

Je l’ai résolu en stockant l’intent comme un paramètre que j’ai traité plus tard dans onResume() .

Il existe deux méthodes DialogFragment show () – show(FragmentManager manager, Ssortingng tag) et show(FragmentTransaction transaction, Ssortingng tag) .

Si vous souhaitez utiliser la version FragmentManager de la méthode (comme dans la question d’origine), une solution simple consiste à remplacer cette méthode et à utiliser commitAllowingStateLoss:

 public class MyDialogFragment extends DialogFragment { @Override public void show(FragmentManager manager, Ssortingng tag) { FragmentTransaction ft = manager.beginTransaction(); ft.add(this, tag); ft.commitAllowingStateLoss(); } } 

Remplacer show(FragmentTransaction, Ssortingng) cette façon n’est pas aussi facile car il devrait également modifier certaines variables internes dans le code DialogFragment d’origine, donc je ne le recommanderais pas – si vous voulez utiliser cette méthode, essayez les suggestions dans le fichier accepté. réponse (ou le commentaire de Jeffrey Blattman).

L’utilisation de commitAllowingStateLoss présente certains risques: la documentation indique “Like commit () mais permet l’exécution de la validation après la sauvegarde de l’état d’une activité. Ceci est dangereux car la validation peut être restaurée ultérieurement. , cela ne doit donc être utilisé que dans les cas où l’état de l’interface utilisateur change de manière inattendue pour l’utilisateur. ”

EDIT: Encore une autre option, et peut-être la meilleure encore (ou du moins ce que la bibliothèque de support attend …)

Si vous utilisez DialogFragments avec la bibliothèque de support Android, vous devriez utiliser une sous-classe de FragmentActivity. Essayez ce qui suit:

 onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, intent); //other code ProgressFragment progFragment = new ProgressFragment(); progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG); // other code } 

J’ai jeté un coup d’oeil à la source pour FragmentActivity, et il semble qu’il appelle un gestionnaire de fragment interne afin de reprendre des fragments sans perte d’état.


J’ai trouvé une solution qui n’est pas répertoriée ici. Je crée un gestionnaire et lance le fragment de dialog dans le gestionnaire. Donc, éditer un peu votre code:

 onActivityResult(int requestCode, int resultCode, Intent data) { //other code final FragmentManager manager = getActivity().getSupportFragmentManager(); Handler handler = new Handler(); handler.post(new Runnable() { public void run() { ProgressFragment progFragment = new ProgressFragment(); progFragment.show(manager, PROG_DIALOG_TAG); } }); // other code } 

Cela me semble plus propre et moins piraté.

Vous ne pouvez pas afficher la boîte de dialog après l’activité attachée appelée sa méthode onSaveInstanceState (). Évidemment, onSaveInstanceState () est appelé avant onActivityResult (). Donc, vous devriez afficher votre boîte de dialog dans cette méthode de rappel OnResumeFragment (), vous n’avez pas besoin de remplacer la méthode show () de DialogFragment. J’espère que ceci vous aidera.

J’ai conçu une troisième solution, basée en partie sur la solution de hmt. Fondamentalement, créez un ArrayList de DialogFragments, à afficher sur onResume ();

 ArrayList dialogList=new ArrayList(); //Some function, like onActivityResults { DialogFragment dialog=new DialogFragment(); dialogList.add(dialog); } protected void onResume() { super.onResume(); while (!dialogList.isEmpty()) dialogList.remove(0).show(getSupportFragmentManager(),"someDialog"); } 

onActivityResult () s’exécute avant onResume (). Vous devez faire votre interface utilisateur dans onResume () ou plus tard.

Utilisez un booléen ou tout ce dont vous avez besoin pour communiquer qu’un résultat est revenu entre ces deux méthodes.

… C’est tout. Simple.

Je sais que cela a été répondu il y a pas mal de temps .. mais il existe un moyen beaucoup plus facile de faire cela que certaines des autres réponses que j’ai vues ici … Dans mon cas spécifique, je devais montrer un DialogFragment à partir d’un fragment onActivityResult () méthode.

Ceci est mon code pour gérer cela, et ça marche à merveille:

 DialogFragment myFrag; //Don't forget to instantiate this FragmentTransaction trans = getActivity().getSupportFragmentManager().beginTransaction(); trans.add(myFrag, "MyDialogFragmentTag"); trans.commitAllowingStateLoss(); 

Comme mentionné dans certains autres articles, commettre avec une perte d’état peut causer des problèmes si vous ne faites pas attention … dans mon cas, je affichais simplement un message d’erreur à l’utilisateur avec un bouton pour fermer la boîte de dialog, donc l’état de ce qui est perdu n’est pas un gros problème.

J’espère que cela t’aides…

C’est une vieille question mais j’ai résolu de la manière la plus simple, je pense:

 getActivity().runOnUiThread(new Runnable() { @Override public void run() { MsgUtils.toast(getSsortingng(R.ssortingng.msg_img_saved), getActivity().getApplicationContext()); } }); 

La solution la plus propre que j’ai trouvée est la suivante:

 @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { new Handler().post(new Runnable() { @Override public void run() { onActivityResultDelayed(requestCode, resultCode, data); } }); } public void onActivityResultDelayed(int requestCode, int resultCode, Intent data) { // Move your onActivityResult() code here. } 

J’ai eu cette erreur en faisant .show(getSupportFragmentManager(), "MyDialog"); en activité.

Essayez .show(getSupportFragmentManager().beginTransaction(), "MyDialog"); premier.

Si cela ne fonctionne toujours pas, cet article ( Show DialogFragment from onActivityResult ) m’aide à résoudre le problème.

Autrement:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case Activity.RESULT_OK: new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message m) { showErrorDialog(msg); return false; } }).sendEmptyMessage(0); break; default: super.onActivityResult(requestCode, resultCode, data); } } private void showErrorDialog(Ssortingng msg) { // build and show dialog here } 

il suffit d’appeler super.onActivityResult(requestCode, resultCode, data); avant de manipuler le fragment

Cela se produit car lorsque #onActivityResult () est appelée, l’activité parente a déjà appelé #onSaveInstanceState ()

J’utiliserais un Runnable pour “enregistrer” l’action (afficher la boîte de dialog) sur #onActivityResult () pour l’utiliser plus tard lorsque l’activité est prête.

Avec cette approche, nous veillons à ce que l’action que nous souhaitons fasse toujours

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == YOUR_REQUEST_CODE) { mRunnable = new Runnable() { @Override public void run() { showDialog(); } }; } else { super.onActivityResult(requestCode, resultCode, data); } } @Override public void onStart() { super.onStart(); if (mRunnable != null) { mRunnable.run(); mRunnable = null; } } 

Comme vous le savez, ce problème est dû au fait que onActivityResult () appelle avant onstart (), alors appelez simplement onstart () au début de onActivityResult () comme je l’ai fait dans ce code

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { onStart(); //write you code here }