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)
4 Réponses :
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.
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();
é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.
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");
Vous pouvez effectuer une vérification rapide de votre code avant d'ouvrir le fragment:
if(myFragment.isAdded()){ return; } // else continue with code
pourquoi voudrait-on utiliser
AlertDialog.Builder
dans unDialogFragment
? Ç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 unDialogFragment
; 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.