4
votes

Android java.lang.IllegalStateException: Fragment déjà ajouté

Je reçois un objet de chargement en attente d'une requête du webservice. Mais parfois, cet objet entraîne la fin de mon application. Je n'ai pas pu détecter exactement ce qu'impliquait l'erreur.

Pour éviter cette erreur, j'ai appelé l'objet "ignorer" et "annuler" en passant l'activité, mais cela n'a pas fonctionné. J'ai alors assigné une valeur de "null" qui n'a pas fonctionné non plus. Je n'ai plus travaillé parce que je pensais avoir affaire à Tag.

Mon code d'erreur;

    public class DelayedProgressDialog extends DialogFragment {
    private static final int DELAY_MILLISECOND = 450;
    private static final int MINIMUM_SHOW_DURATION_MILLISECOND = 300;
    private static final int PROGRESS_CONTENT_SIZE_DP = 80;

    private ProgressBar mProgressBar;
    private boolean startedShowing;
    private long mStartMillisecond;
    private long mStopMillisecond;

    private FragmentManager fragmentManager;
    private String tag;
    private Handler showHandler;

    // default constructor. Needed so rotation doesn't crash
    public DelayedProgressDialog() {
        super();
    }

    @NonNull
    @SuppressLint("InflateParams")
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = getActivity().getLayoutInflater();

        builder.setView(inflater.inflate(R.layout.dialog_progress, null));
        return builder.create();
    }

    @Override
    public void onStart() {
        super.onStart();
        mProgressBar = getDialog().findViewById(R.id.progress);

        if (getDialog().getWindow() != null) {
            int px = (int) (PROGRESS_CONTENT_SIZE_DP * getResources().getDisplayMetrics().density);
            getDialog().getWindow().setLayout(px, px);
            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        }
    }

    @Override
    public void show(FragmentManager fm, String tag) {
        if (isAdded())
            return;

        this.fragmentManager = fm;
        this.tag = tag;
        mStartMillisecond = System.currentTimeMillis();
        startedShowing = false;
        mStopMillisecond = Long.MAX_VALUE;

        showHandler = new Handler();
        showHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // only show if not already cancelled
                if (mStopMillisecond > System.currentTimeMillis())
                    showDialogAfterDelay();
            }
        }, DELAY_MILLISECOND);
    }

    private void showDialogAfterDelay() {
        startedShowing = true;

        DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(tag);
        if (dialogFragment != null) {
            fragmentManager.beginTransaction().show(dialogFragment).commitAllowingStateLoss();
        } else {
            FragmentTransaction ft = fragmentManager.beginTransaction();
            ft.add(this, tag);
            ft.commitAllowingStateLoss();
        }
    }

    public void cancel() {
        if(showHandler == null)
            return;

        mStopMillisecond = System.currentTimeMillis();
        showHandler.removeCallbacksAndMessages(null);

        if (startedShowing) {
            if (mProgressBar != null) {
                cancelWhenShowing();
            } else {
                cancelWhenNotShowing();
            }
        } else
            dismiss();
    }

    private void cancelWhenShowing() {
        if (mStopMillisecond < mStartMillisecond + DELAY_MILLISECOND + MINIMUM_SHOW_DURATION_MILLISECOND) {
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    dismiss();
                }
            }, MINIMUM_SHOW_DURATION_MILLISECOND);
        } else {
            dismiss();
        }
    }

    private void cancelWhenNotShowing() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                dismiss();
            }
        }, DELAY_MILLISECOND);
    }

    @Override
    public void dismiss() {
        FragmentTransaction ft = fragmentManager.beginTransaction();
        ft.remove(this);
        ft.commitAllowingStateLoss();
    }
}

Ma classe de dialogue de progression d'utilisation; p >

2019-03-27 11:51:20.502 29685-29685/com.xxxx.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xxxx.app, PID: 29685
    java.lang.IllegalStateException: Fragment already added: DelayedProgressDialog{d8bd442 #1 Delaleyed}
        at androidx.fragment.app.FragmentManagerImpl.addFragment(FragmentManager.java:1916)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:765)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
        at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:6981)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)


8 commentaires

pourquoi voudrait-on utiliser AlertDialog.Builder dans un DialogFragment ? Ça n'a pas de sens.


@MartinZeitler pour être comme ça github.com/Q115/DelayedProgressDialog


cela n'a toujours pas de sens, car un AlertDialog a généralement peu à voir avec un DialogFragment ; c'est l'un ou l'autre, mais pas l'un instanciant l'autre. seulement parce que quelqu'un l'a poussé vers GitHub n'implique pas que cela aurait du sens. signalez-y un problème si vous rencontrez des problèmes.


@MartinZeitler Vous avez raison. Avez-vous une solution pour ce sujet?


ce n'est probablement pas mon travail. utilisez simplement un DialogFragment ... sans encombrement.


@MartinZeitler Très bien. Merci d'être intéressé.


Existe-t-il un moyen de vérifier que le fragment est actif?


J'ai eu le même problème après avoir intégré Koin pour injecter mes modèles de vue dans ce fragment. Et j'ai oublié de lancer la classe d'application. Donc, mes composants Koin n'ont pas été injectés dans Fragment.


4 Réponses :


2
votes

Modifiez simplement private void showDialogAfterDelay () . Vous devez vérifier si la boîte de dialogue est déjà ajoutée;

Ajoutez: if (dialogFragment! = null && dialogFragment.isAdded ()) {return; }

Ce code doit s'exécuter avant d'essayer d'afficher la boîte de dialogue.


0 commentaires

8
votes

J'ai enfin trouvé la solution. Je cherchais des balises avec "findFragmentByTag" dans ma fonction "showDialogAfterDelay". Mais cela ne s'est jamais réalisé. Je n'ai pas pu déterminer si c'était "Ajouté". Le morceau de code que j'utilise pour résoudre ce problème;

        fragmentManager.executePendingTransactions();


1 commentaires

également selon la documentation Si vous validez une seule transaction qui ne modifie pas la pile arrière de fragments, envisagez fortement d'utiliser commitNow () à la place. Cela peut aider à éviter les effets secondaires indésirables lorsqu'un autre code de votre application a des transactions validées en attente qui prévoient un timing différent.



1
votes

Vous devez vérifier si le dialogFragment est déjà ajouté; Si dialogFragment n'est pas ajouté, affichez-le:

if (fragmentManager.findFragmentByTag("progress_dialog") == null) 
    dialogFragment.show(getSupportFragmentManager(), "progress_dialog");


0 commentaires

0
votes

Vous pouvez effectuer une vérification rapide de votre code avant d'ouvrir le fragment:

    if(myFragment.isAdded()){
       return;
    }
// else continue with code


0 commentaires