Afficher le fragment de dialogue de onActivityResult

j'ai le code suivant dans mon onActivityResult pour un de mes fragments:

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

Cependant, j'obtiens 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 arranger ça? Je dois noter que j'utilise le pack de support Android.

74
demandé sur Kurtis Nusbaum 2012-04-12 01:33:27

17 réponses

si vous utilisez Android Support library, la méthode onResume n'est pas le bon endroit, où 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 point de 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);
    }
  }
}
67
répondu Arcao 2014-11-17 11:07:59

EDIT: Pas un bug, mais plutôt un défaut dans le cadre des fragments. La meilleure réponse à cette question est celle fournie par @Arcao ci-dessus.

---- message d'Origine ----

en fait c'est un bogue connu avec le paquet support (edit: not actually a bug. voir le commentaire de @alex-lockwood). Un travail posté dans les commentaires du rapport de bogue est de modifier la source du DialogFragment comme suit:

public int show(FragmentTransaction transaction, String tag) {
    return show(transaction, tag, false);
}


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

Note Ceci est un hack géant. La façon dont je l'ai fait, c'était juste faire mon propre fragment de dialogue que je pouvais enregistrer à partir du fragment original. Quand cet autre fragment de dialogue a fait des choses (comme être rejeté), il a dit à tous les auditeurs qu'il allait disparaître. Je l'ai fait comme ceci:

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.string.password_required);
     return v;
 }

 public void passwordEntered(){
   //TODO handle if they didn't type anything in
   playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toString());
   dismiss();
 }

 public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){
   this.playerListFragment = playerListFragment;
 }

 public void unregisterPasswordEnteredListener(){
   this.playerListFragment = null;
 }
}

donc maintenant j'ai un moyen de notifier le fragment Playerlist quand les choses se produisent. Notez que c'est très important que vous appeliez unnisterpasswordenteredlistener de manière appropriée (dans le cas ci-dessus lorsque le fragment PlayerListFragment "s'en va"), sinon ce fragment de dialogue pourrait essayer d'appeler des fonctions sur l'écouteur enregistré lorsque celui-ci n'existe plus.

26
répondu Kurtis Nusbaum 2016-04-04 23:41:50

le commentaire laissé par @Natix est un paquetage rapide que certaines personnes ont peut-être enlevé.

la solution la plus simple à ce problème est d'appeler super.onActivityResult () avant d'exécuter votre propre code. Cela fonctionne indépendamment du fait que vous utilisez ou non la bibliothèque de soutien et maintient la cohérence comportementale dans votre activité.

il y a:

plus je lis dans ce les plus fous hacks que j'ai vu.

si vous rencontrez encore des problèmes, alors celui de Alex Lockwood est celui à vérifier.

16
répondu twig 2017-05-23 11:54:53

appels Android onActivityResult() avant onStart() .

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

14
répondu hrnt 2013-08-20 23:15:17

il y a deux méthodes de dialogue show () - show(FragmentManager manager, String tag) et show(FragmentTransaction transaction, String tag) .

si vous voulez utiliser la version FragmentManager de la méthode( comme dans la question originale), une solution facile est de passer outre cette méthode et d'utiliser la perte de commitallowingstatt:

public class MyDialogFragment extends DialogFragment {

  @Override 
  public void show(FragmentManager manager, String tag) {
      FragmentTransaction ft = manager.beginTransaction();
      ft.add(this, tag);
      ft.commitAllowingStateLoss();
  }

}

Substitution show(FragmentTransaction, String) de cette façon, n'est pas aussi facile, car il faut aussi modifier certaines variables internes au sein de l'origine DialogFragment code, donc je ne le recommande pas - si vous voulez utiliser cette méthode, puis essayez les suggestions accepté de répondre (ou le commentaire de Jeffrey Blattman).

l'utilisation de commitallowingstatteloss comporte un certain risque: la documentation indique" comme commit() mais permet d'exécuter la propagation après avoir sauvegardé l'état d'une activité. C'est dangereux parce que la propagation peut être perdue si l'activité doit être restaurée plus tard de son état, donc cela ne devrait être utilisé que pour les cas où il est correct pour L'état UI pour changer de façon inattendue sur l'utilisateur."

9
répondu gkee 2013-04-25 03:46:35

EDIT: Encore l'autre option, et peut-être le meilleur encore (ou du moins ce que la bibliothèque de prise en charge en attend...)

si vous utilisez DialogFragments avec la bibliothèque de support Android, vous devez 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 oeil à la source 1519100920 "pour FragmentActivity, et il semble qu'il appelle un gestionnaire de fragment interne afin de reprendre les fragments sans perdre l'état.


j'ai trouvé une solution qui n'est pas listée ici. Je crée un gestionnaire, et démarre le fragment de dialogue dans le Gestionnaire. Donc, modifier 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 macabre.

9
répondu Simon Jacobs 2014-05-02 18:12:38

vous ne pouvez pas afficher le dialogue après l'activité attachée appelée sa méthode onSaveInstanceState(). Évidemment, onSaveInstanceState () est appelé avant onActivityResult (). Vous devriez donc afficher votre dialogue dans cette méthode de callback OnResumeFragment (), vous n'avez pas besoin de surcharger la méthode show () de DialogFragment. Espérons que cela vous aidera.

4
répondu handrenliang 2013-05-24 01:56:49

j'ai trouvé une troisième solution, basée en partie sur la solution de hmt. Fondamentalement, créer un ArrayList de fragments de dialogues, à montrer sur onResume ();

ArrayList<DialogFragment> dialogList=new ArrayList<DialogFragment>();

//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");
}
3
répondu PearsonArtPhoto 2012-12-18 03:21:19

onActivityResult() execute before onResume(). Vous devez faire votre UI 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.

3
répondu Eurig Jones 2013-07-29 14:52:42

je sais que cela a été répondu il y a un certain temps.. mais il y a une façon beaucoup plus facile de le faire que certaines des autres réponses que j'ai vu ici... Dans mon cas spécifique, j'ai dû montrer un fragment de dialogue à partir d'une méthode de fragment onActivityResult ().

C'est mon code pour gérer ça, et ça marche très bien:

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

comme il a été mentionné dans certains des autres messages, commettre avec perte d'état peut causer des problèmes si vous n'êtes pas prudent... dans dans mon cas, j'affichais simplement un message d'erreur à l'utilisateur avec un bouton pour fermer le dialogue, donc si l'état de celui-ci est perdu, ce n'est pas une grosse affaire.

Espérons que cette aide...

2
répondu Justin 2013-06-13 06:29:34

c'est une vieille question mais j'ai résolu par le moyen le plus simple, je pense:

getActivity().runOnUiThread(new Runnable() {
    @Override
        public void run() {
            MsgUtils.toast(getString(R.string.msg_img_saved),
                    getActivity().getApplicationContext());
        }
    });
2
répondu LucasBatalha 2015-10-01 14:10:43

la solution la plus propre que j'ai trouvée est celle-ci:

@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.
}
0
répondu fhucho 2013-11-03 13:59:19

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

Essayer .show(getSupportFragmentManager().beginTransaction(), "MyDialog"); en premier.

S'il ne fonctionne toujours pas, ce post ( montrer le fragment de dialogue de onActivityResult ) m'aide à résoudre le problème.

0
répondu Youngjae 2017-05-23 12:02:41

une autre voie:

@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(String msg) {
    // build and show dialog here
}
0
répondu Maher Abuthraa 2017-06-22 04:52:02

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

0
répondu Thomas Klammer 2017-07-20 14:47:01

cela arrive parce que quand #onActivityResult () est appelé, l'activité mère a déjà appelé #onSaveInstanceState ()

j'utiliserais un Runnable pour" sauvegarder " l'action (Afficher la boîte de dialogue) sur #onActivityResult() pour l'utiliser plus tard lorsque l'activité est prête.

Avec cette approche, nous assurez-vous que l'action que nous voulons toujours travailler

@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;
    }
}
0
répondu Ricard 2017-08-31 15:39:58

Comme vous le savez tous ce problème est en raison de l'onActivityResult() appelle avant onstart(),donc il suffit d'appeler onstart() au début de onActivityResult() comme j'ai fait dans ce code

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      onStart();
      //write you code here
}
-2
répondu Bunny Bandewar 2015-04-08 06:01:08