How Android DialogFragment shows and hides

1. The foregoing

DialogFragment can be understood from the name: it is a fragment and has the characteristics of a dialog.

2. Program

Regarding the display, FragmentTransaction can be used because it is a Fragment itself.
About dismiss:

@Override
public void onDismiss(@NonNull DialogInterface dialog) {
    if (!mViewDestroyed) {
        // Note: we need to use allowStateLoss, because the dialog
        // dispatches this asynchronously so we can receive the call
        // after the activity is paused.  Worst case, when the user comes
        // back to the activity they see the dialog again.
        dismissInternal(true, true);
    }
}

void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss) {
    if (mDismissed) {
        return;
    }
    mDismissed = true;
    mShownByMe = false;
    if (mDialog != null) {
        // Instead of waiting for a posted onDismiss(), null out
        // the listener and call onDismiss() manually to ensure
        // that the callback happens before onDestroy()
        mDialog.setOnDismissListener(null);
        mDialog.dismiss();
        if (!fromOnDismiss) {
            // onDismiss() is always called on the main thread, so
            // we mimic that behavior here. The difference here is that
            // we don't post the message to ensure that the onDismiss()
            // callback still happens before onDestroy()
            if (Looper.myLooper() == mHandler.getLooper()) {
                onDismiss(mDialog);
            } else {
                mHandler.post(mDismissRunnable);
            }
        }
    }
    mViewDestroyed = true;
    if (mBackStackId >= 0) {
        requireFragmentManager().popBackStack(mBackStackId,
                FragmentManager.POP_BACK_STACK_INCLUSIVE);
        mBackStackId = -1;
    } else {
        FragmentTransaction ft = requireFragmentManager().beginTransaction();
        ft.remove(this);
        if (allowStateLoss) {
            ft.commitAllowingStateLoss();
        } else {
            ft.commit();
        }
    }
}

It can be found that if DialogFragment.dismiss()the dismiss is triggered by the method or the button is returned, it dismissInternal(true, true);will be called eventually FragmentTransaction.remove(this), which means that the fragment is destroyed. In many cases, it is necessary to keep the status of the pop-up window, but this time it does not meet the requirements.

——> So you can override the onDismiss method.

@Override
    public void onDismiss(DialogInterface dialog) {
        //注释掉super方法调用,因为该方法会使得Fragment销毁
//        super.onDismiss(dialog);
    }

Looking at the source code, you can find that DialogFragment is actually: Fragment is wrapped in Dialog.
Then its display and hiding can actually be realized directly by using dialog.show()or .dialog.hide()

After use getDialog().hide(), when the screen is opened again, the entire pop-up window reappears. The reasons are as follows:

@Override
public void onStart() {
    super.onStart();
    if (mDialog != null) {
        mViewDestroyed = false;
        mDialog.show();
    }
}

@Override
public void onStop() {
    super.onStop();
    if (mDialog != null) {
        mDialog.hide();
    }
}

How to shield the impact of the execution code in the above life cycle on the dialog?

Manually show() or hide() in the life cycle

Is it not possible to comment out super.onStart() directly?

No, it will lead to life cycle disorder. And ide will become popular, because here api (Fragment) uses an annotation: @CallSuper

/**
 * Called when the Fragment is visible to the user.  This is generally
 * tied to {@link Activity#onStart() Activity.onStart} of the containing
 * Activity's lifecycle.
 */
@CallSuper
public void onStart() {
    mCalled = true;
}


//追踪CallSuper定义
/**
 * Denotes that any overriding methods should invoke this method as well.
 * <p>
 * Example:
 * <pre><code>
 *  &#64;CallSuper
 *  public abstract void onFocusLost();
 * </code></pre>
 */
@Documented
@Retention(CLASS)
@Target({METHOD})
public @interface CallSuper {
}

It can be found that all methods annotated by @CallSuper must be called back in the overridden method. Therefore, super.onStart()the or cannot be removed in any case super.onStop().

3. Conclusion

As far as the requirements mentioned in the case are concerned, it is cumbersome to use DialogFragment in this way. It is better to use Dialog to wrap Fragment directly. If you don't know the API, use it with caution.

After reading the article, if it is helpful, don't forget to like or like it!

Guess you like

Origin blog.csdn.net/ganshenml/article/details/120539134