98 votes

Empêcher le rejet de la boîte de dialogue en cas de rotation de l'écran dans Android

J'essaie d'empêcher les boîtes de dialogue construites avec Alert builder d'être rejetées lorsque l'activité est redémarrée.

Si je surcharge la méthode onConfigurationChanged, je peux le faire avec succès et réinitialiser la mise en page à l'orientation correcte, mais je perds la fonction de texte collant de l'edittext. Ainsi, en résolvant le problème du dialogue, j'ai créé ce problème d'edittext.

Si je sauvegarde les chaînes de caractères du texte d'édition et que je les réaffecte dans le changement d'onCofiguration, elles semblent toujours avoir la valeur initiale par défaut et non celle qui a été saisie avant la rotation. Même si je force une invalidation, cela semble les mettre à jour.

J'ai vraiment besoin de résoudre soit le problème du dialogue, soit celui de l'édition du texte.

Merci pour votre aide.

1 votes

Comment enregistrer/restaurer le contenu de l'EditText modifié ? Pouvez-vous montrer un peu de code ?

0 votes

J'ai compris le problème, j'avais oublié de récupérer la vue par Id après avoir réinitialisé la mise en page.

1voto

La meilleure approche est sans aucun doute l'utilisation de DialogFragment.

Voici ma solution de classe wrapper qui permet d'éviter que différents dialogues soient rejetés dans un même Fragment (ou Activité avec une petite refactorisation). De plus, cela permet d'éviter une refactorisation massive du code si, pour une raison ou une autre, il y a beaucoup d'activités de type AlertDialogs éparpillés parmi le code avec de légères différences entre eux en termes d'actions, d'apparence ou autre.

public class DialogWrapper extends DialogFragment {
    private static final String ARG_DIALOG_ID = "ARG_DIALOG_ID";

    private int mDialogId;

    /**
     * Display dialog fragment.
     * @param invoker  The fragment which will serve as {@link AlertDialog} alert dialog provider
     * @param dialogId The ID of dialog that should be shown
     */
    public static <T extends Fragment & DialogProvider> void show(T invoker, int dialogId) {
        Bundle args = new Bundle();
        args.putInt(ARG_DIALOG_ID, dialogId);
        DialogWrapper dialogWrapper = new DialogWrapper();
        dialogWrapper.setArguments(args);
        dialogWrapper.setTargetFragment(invoker, 0);
        dialogWrapper.show(invoker.getActivity().getSupportFragmentManager(), null);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDialogId = getArguments().getInt(ARG_DIALOG_ID);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return getDialogProvider().getDialog(mDialogId);
    }

    private DialogProvider getDialogProvider() {
        return (DialogProvider) getTargetFragment();
    }

    public interface DialogProvider {
        Dialog getDialog(int dialogId);
    }
}

En ce qui concerne l'activité, vous pouvez invoquer getContext() à l'intérieur de onCreateDialog() et l'envoyer au DialogProvider et demander un dialogue spécifique en mDialogId . Toute logique de traitement d'un fragment cible doit être supprimée.

Utilisation d'un fragment :

public class MainFragment extends Fragment implements DialogWrapper.DialogProvider {
    private static final int ID_CONFIRMATION_DIALOG = 0;

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Button btnHello = (Button) view.findViewById(R.id.btnConfirm);
        btnHello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DialogWrapper.show(MainFragment.this, ID_CONFIRMATION_DIALOG);
            }
        });
    }

    @Override
    public Dialog getDialog(int dialogId) {
        switch (dialogId) {
            case ID_CONFIRMATION_DIALOG:
                return createConfirmationDialog(); //Your AlertDialog
            default:
                throw new IllegalArgumentException("Unknown dialog id: " + dialogId);
        }
    }
}

Vous pouvez lire l'article complet sur mon blog Comment éviter que la boîte de dialogue soit rejetée ? et jouer avec le code source .

1voto

BadCash Points 566

Il semble que ce problème persiste, même lorsque l'on fait tout ce qu'il faut et que l'on utilise le système de gestion de l'information. DialogFragment etc.

Il y a un fil de discussion sur Google Issue Tracker qui prétend que cela est dû à un ancien message de renvoi laissé dans la file d'attente des messages. La solution de contournement fournie est assez simple :

    @Override
    public void onDestroyView() {
        /* Bugfix: https://issuetracker.google.com/issues/36929400 */
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);

        super.onDestroyView();
    }

Incroyable que cela soit encore nécessaire 7 ans après que ce problème ait été signalé pour la première fois.

0 votes

1voto

Caumons Points 1702

Une approche très simple consiste à créer les boîtes de dialogue à partir de la méthode onCreateDialog() (voir note ci-dessous). Vous les montrez à travers showDialog() . De cette façon, Android gère la rotation pour vous et vous ne devez pas appeler dismiss() en onPause() pour éviter une WindowLeak et ensuite vous n'aurez pas non plus à restaurer le dialogue. De la docs :

Montrez un dialogue géré par cette activité. Un appel à onCreateDialog(int, Bundle) sera effectué avec le même identifiant la première fois qu'il sera appelé pour un identifiant donné. Par la suite, le dialogue sera automatiquement sauvegardé et restauré.

Voir Documentation Android showDialog() pour plus d'informations. J'espère que cela aidera quelqu'un !

Note : Si vous utilisez AlertDialog.Builder, ne faites pas appel à show() de onCreateDialog() appel create() à la place. Si vous utilisez ProgressDialog, il suffit de créer l'objet, de définir les paramètres dont vous avez besoin et de le renvoyer. En conclusion, show() à l'intérieur de onCreateDialog() pose des problèmes, il suffit de créer une instance de Dialog et de la renvoyer. Cela devrait fonctionner ! (J'ai rencontré des problèmes en utilisant showDialog() à partir de onCreate() -en fait, le dialogue n'est pas affiché-, mais si vous l'utilisez dans onResume() ou dans un callback de listener, cela fonctionne bien).

0 votes

Dans quel cas auriez-vous besoin d'un code ? Le onCreateDialog() ou l'afficher avec le builder et appeler show() ?

0 votes

J'ai réussi à le faire mais le problème est que onCreateDialog() est maintenant déprécié :-\

0 votes

OK ! Gardez à l'esprit que la plupart des appareils Android fonctionnent encore avec les versions 2.X, vous pouvez donc l'utiliser quand même ! Jetez un coup d'œil à Utilisation des versions de la plate-forme Android

0voto

hackjutsu Points 2476

Vous pouvez combiner les Dialogues onSave/onRestore avec les méthodes Activité surSave/onRestore pour conserver l'état de la boîte de dialogue.

Note : Cette méthode fonctionne pour les boîtes de dialogue "simples", comme l'affichage d'un message d'alerte. Elle ne reproduira pas le contenu d'une WebView intégrée dans une boîte de dialogue. Si vous voulez vraiment empêcher le rejet d'un dialogue complexe pendant la rotation, essayez la méthode de Chung IW.

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
     super.onRestoreInstanceState(savedInstanceState);
     myDialog.onRestoreInstanceState(savedInstanceState.getBundle("DIALOG"));
     // Put your codes to retrieve the EditText contents and 
     // assign them to the EditText here.
}

@Override
protected void onSaveInstanceState(Bundle outState) {
     super.onSaveInstanceState(outState);
     // Put your codes to save the EditText contents and put them 
     // to the outState Bundle here.
     outState.putBundle("DIALOG", myDialog.onSaveInstanceState());
}

0voto

Sam Points 3542

J'ai eu un problème similaire : lorsque l'orientation de l'écran changeait, la boîte de dialogue onDismiss a été appelé même si l'utilisateur n'a pas rejeté la boîte de dialogue. J'ai pu contourner ce problème en utilisant plutôt la fonction onCancel qui se déclenche à la fois lorsque l'utilisateur appuie sur le bouton retour et lorsqu'il touche l'extérieur de la boîte de dialogue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X