web-dev-qa-db-ja.com

Android Java.lang.IllegalStateException:フラグメントはすでに追加されています

Webサービスからのリクエストを待機する読み込みオブジェクトを取得しています。しかし、このオブジェクトが原因でアプリケーションが終了することがあります。エラーの原因を正確に検出できませんでした。

このエラーを防ぐために、アクティビティを渡すときにオブジェクトを「破棄」および「キャンセル」と呼びましたが、これは機能しませんでした。次に、「null」の値を割り当てましたが、これも機能しませんでした。私はタグを扱っていると思ったので、二度と仕事をしませんでした。

私のエラーコード。

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)

私の使用状況ダイアログクラス。

    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();
    }
}
4
Hasan Kucuk

dialogFragmentがすでに追加されているかどうかを確認する必要があります。 dialogFragmentが追加されていない場合は、それを表示します。

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