DialogFramengt学习

一.我们为什么要使用DialogFragment?

  1. 生命周期管理:DialogFragment具有自己的生命周期,与Activity的生命周期相互独立。这使得在旋转屏幕或配置更改等情况下,DialogFragment能够更好地处理状态保存和恢复。而Dialog需要手动管理这些生命周期事件。

  2. 灵活的界面管理:DialogFragment可以在布局文件中定义自己的用户界面,使界面的创建和管理更加灵活。你可以使用XML布局或通过编程方式构建界面。而Dialog通常需要使用代码编程方式创建和配置界面。

  3. 与Fragment交互:DialogFragment可以与其所属的Activity和其他Fragment进行交互。它可以通过回调接口、观察者模式或使用Fragment的方法来实现与Activity和其他Fragment之间的通信。而Dialog通常无法直接与Activity和其他Fragment进行交互。

  4. 设备兼容性:DialogFragment提供了更好的设备兼容性。它可以适应不同尺寸的屏幕,并在平板电脑和手机上提供一致的用户体验。而Dialog的样式和大小可能在不同设备上显示不一致。

  5. 管理和复用:DialogFragment可以由FragmentManager进行管理,使得显示、隐藏、替换和移除更加方便。它也可以通过标签进行识别和查找,便于在需要时重新显示或操作。而Dialog通常需要手动管理其显示和隐藏,并且难以实现复用。

综上所述,DialogFragment相较于Dialog具有更好的生命周期管理、界面灵活性、与Fragment交互、设备兼容性和管理复用等方面的优势。因此,在大多数情况下,推荐使用DialogFragment来实现对话框式的用户界面。

二.简单的使用

DialogFragment的本质是使用Fragmnet来管理Dialog的生命周期。

第一步:创建对话框布局文件 ldialig_fragment_custom.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="#ECE1E1"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingTop="20dp">
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="第一个Dialog"
        android:textSize="20sp"
        android:textStyle="bold" />
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="20dp"
        android:background="#999999" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/tv_close"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_gravity="bottom"
            android:layout_weight="1"
            android:gravity="center"
            android:text="取消"
            android:textSize="18sp" />
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="#999999" />
        <TextView
            android:id="@+id/tv_confirm"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_gravity="bottom"
            android:layout_weight="1"
            android:gravity="center"
            android:text="确定"
            android:textColor="#3085CE"
            android:textSize="18sp" />
    </LinearLayout>
</LinearLayout>

注意:这里的根布局里设置没有生效,我们需要去代码里面设置。

第二步:自定义DialogFragmnet

public class CustomDialogFragment extends DialogFragment {
    private View mView;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mView = inflater.inflate(R.layout.dialig_fragment_custom, container, false);
        return mView;
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initWindow();
        initView();
    @Override
    public void onResume() {
        super.onResume();
    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        super.onDismiss(dialog);
    private void initWindow() {
        if (getDialog() != null) {
            //初始化window相关表现
            Window window = getDialog().getWindow();
            //设置window宽高(单位px)
            window.getAttributes().width = 700;
            //设置window位置:居中
            window.getAttributes().gravity = Gravity.CENTER;
    private void initView() {
        TextView button1 = mView.findViewById(R.id.tv_confirm);
        button1.setOnClickListener(v -> {
            Toast.makeText(getContext(), "mgs", Toast.LENGTH_SHORT).show();
            dismiss();
        });

我这里自定义的很简单,应该也不难理解。

第三步:在Activity中展示DialogFragment

CustomDialogFragment customDialogFragment = new CustomDialogFragment();
customDialogFragment.showNow(getSupportFragmentManager(), "customDialogFragment");

以上三步,就可以实现dialog的弹出。

其他效果:

  1. 点击返回键不消失DialogFragment

     customDialogFragment.getDialog().setOnKeyListener(new DialogInterface.OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    return keyCode == KeyEvent.KEYCODE_BACK;
            });
    
  2. 点击弹窗外部,弹窗消失

      if (customDialogFragment.getDialog() != null) {
                customDialogFragment.getDialog().setCancelable(true);
    

    还有很多…比如弹出动画,可以根据自己需要在网上搜索

三.分析源码

1.方法的作用:用于在 DialogFragment 内部进行 dismiss 操作。

  1. boolean allowStateLoss :是否允许状态丢失
  2. boolean fromOnDismiss:是否由onDismiss方法触发
 private void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss) {
        if (mDismissed) {
            return;
      //mDismissed标志设置为 true,表示已经进行了 dismiss 操作
      //mShownByMe 标志设置为 false,表示 DialogFragment 不再处于显示状态。
        mDismissed = true;
        mShownByMe = false;
        if (mDialog != null) {
            mDialog.setOnDismissListener(null);
            mDialog.dismiss();
            if (!fromOnDismiss) {
                //判断当前线程是否为主线程
                if (Looper.myLooper() == mHandler.getLooper()) {
                    onDismiss(mDialog);
                } else {
                    mHandler.post(mDismissRunnable);
      //mViewDestroyed 标志设置为 true,表示 DialogFragment 的视图已被销毁
        mViewDestroyed = true;
      //DialogFragment 在回退栈中有对应的 ID,进行弹出栈,否则提交事物
        if (mBackStackId >= 0) {
            getParentFragmentManager().popBackStack(mBackStackId,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
            mBackStackId = -1;
        } else {
            FragmentTransaction ft = getParentFragmentManager().beginTransaction();
            ft.remove(this);
            if (allowStateLoss) {
                ft.commitAllowingStateLoss();
            } else {
                ft.commit();
1.什么是提交事物?

如果只给出一个提交事物的名词,也行并不能理解这块代码。那么什么是提交事物?

​ 提交事务是将对 Fragment 的操作(添加、移除、替换等)应用到 Fragment 管理器中的一种方式。事务用于将一系列的 Fragment 操作封装在一起,并确保这些操作以原子方式执行,从而保持 Fragment 管理器的一致性。

  getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, fragment)
                    .commit();

上面的代码是不是很眼熟,fragment的动态替换。

通过提交事务,我们可以保证 Fragment 操作的原子性、批量执行、事务回退和状态保存等功能,提供了一种可靠和一致的方式来管理 Fragment 的添加、移除、替换等操作,并确保 Fragment 管理器的正确性和稳定性。

2.commitAllowingStateLoss()和commit()

这两个都是提交事物,但是有一些不同,从我们allowStateLoss的判断就可以看出来,对于commitAllowingStateLoss()来说,允许在状态丢失的情况下提交事务,并在 Activity 重建后尝试恢复事务状态。举例的话,就是我们屏幕旋转之后,会和我们旋转之前的状态一样。对于commit()来说,如果在事务提交之前发生 Activity 的状态保存过程(如屏幕旋转)或进程被销毁重建,那么在恢复状态时,如果事务尚未执行完毕,会抛出 IllegalStateException 异常,从而导致事务丢失。

- commit() 提交事务时,如果在事务提交之前发生状态保存或进程重建,可能会导致事务丢失并抛出异常。
- commitAllowingStateLoss() 提交事务时,在状态丢失的情况下也能够提交事务,但可能会导致一些副作用。如无法通过事务回退来撤销操作
- 如果事务的状态对于应用程序的正确性至关重要,应优先考虑使用 commit(),并通过适当的处理来避免状态丢失。仅在确定状态丢失不会造成严重问题的情况下,才考虑使用 commitAllowingStateLoss()

3.为什么fragment已经不在回退栈内,为什么还需要提交事物?
  • 如果你仔细看代码就会发现上述的问题,fragment不在回退栈,那么当前的实例应该已经销毁了,生命周期已经结束了。我们还提交事物干嘛?

提交事务的目的不是为了维护 DialogFragment 的生命周期,而是为了确保对 FragmentManager 的操作正确执行。

即使 DialogFragment 已经被销毁,调用 FragmentTransactionremove() 方法仍然是必要的。这是因为该操作会通知 FragmentManager 移除相关的 Fragment,并更新其内部状态,以便在下一次事务提交或回退栈操作时得到正确的处理。

提交事务不仅仅用于处理当前存在的 Fragment 实例,它还用于更新 FragmentManager 的状态和维护其内部数据结构。这对于后续的事务操作、回退栈管理和其他操作是必要的。因此,即使 DialogFragment 已被销毁,提交事务仍然是需要的。

总结起来,提交事务的目的不是为了维护 DialogFragment 的生命周期,而是为了确保对 FragmentManager 的操作能够正确执行和同步。即使 DialogFragment 不在回退栈中并已被销毁,提交事务仍然是必要的,以确保 FragmentManager 的状态和内部数据结构保持一致和可靠。

  • 那我们什么时候会执行下面的提交事物的方法呢?

我理解的一种情况:连续进行dismiss操作的情况下可能会发生。因为这个代码块并没有进行加锁操作。所以可能会有同步操作。

2.方法的作用:显示dialogFragmnet

public void showNow(@NonNull FragmentManager manager, @Nullable String tag) {
    mDismissed = false;
    mShownByMe = true;
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commitNow();

他还有几个相似的方法:

public void show(@NonNull FragmentManager manager, @Nullable String tag) {
    mDismissed = false;
    mShownByMe = true;
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commit();
public int show(@NonNull FragmentTransaction transaction, @Nullable String tag) {
    mDismissed = false;
    mShownByMe = true;
    transaction.add(this, tag);
    mViewDestroyed = false;
    mBackStackId = transaction.commit();
    return mBackStackId;
  • 实现的效果都是一样的,我们这里优先使用showNow方法,至于为什么?

1.show要比showNow稍微“慢”一点,这导致调用show了后,立刻修改dialog中的view(例如textView修改字符内容)会崩溃,而showNow不会
先在FirstDialogFragment中添加方法:

    fun setContent(text: String) {
        tv_content.text = text

以下代码会崩溃:

        val firstDialog = FirstDialogFragment()
        firstDialog.show(supportFragmentManager, "First")
        firstDialog.setContent("Hello")

以下代码则正常执行(对话框内容被修改为Hello):

        val firstDialog = FirstDialogFragment()
        firstDialog.showNow(supportFragmentManager, "First")
        firstDialog.setContent("Hello")
                                    DialogFragment实现对话框对话框在项目正很常见,以前做项目我基本上都是用AlertDialog实现对话框。DialogFragment出现以后,我就很少再用其他方式实现对话框交互了。几乎所有项目中的弹框都通过DialogFragment实现。这篇文章从以下几个角度总结使用DialogFragment:
基本对话框实现
Alert Dialog实现Markdown和扩展Markd
                                    在开始学习 Android 的时候,制作对话框,无疑都是直接使用 Dialog,然后对其进行自定义,而后面推出 DialogFragment 后,更多人都开始使用 DialogFragment 了,那么,DialogFragmentDialog 到底有什么区别?首先,我们来分析下 DialogFragment。...
                                    一、DialogFragment 的说明:
Android官方推荐在Android 3.0之后,使用 DialogFragment 来代替 Dialog
二、DialogFragment 的介绍:
1、DialogFragment是什么?
首先 DialogFragment 继承自 Fragment, 实现了 DialogInterface 的两个接口,其本质是 Fragment,
它持有了一个Dialog对象。
这就意味着,DialogFragment 替我们管理了 Dialog,而我们其实使用的是一个含
                                    DialogmentFragment详细的生命周期为:
1.onAttach(Activity):
当Activity与Fragment发生关联时调用(已废弃,但是还是调用了)
2.onAttach(Context):当Activity与Fragment发生关联时调用
3.onCreate(Bundle):初始化Fragment。可通过参数savedInstanceState获取之前保存的值
4....
                                    之前一篇文章Dialog使用介绍介绍了DialogFragemnt的一些使用常识,本文来简单介绍DialogFragment常用的生命周期函数,调用顺序如下:onAttach -->onCreate-->onCreateDialog-->onCreateView-->onViewCreated-->onSaveInstanceState在onAttach里传入要att...
​图 1 Fragment生命周期流程图
除了上述声明周期之外,也可以注册FragmentLifecycleCallbacks来插入更多Fragment状态的监听,具体有:
public abstract static class FragmentLifecycleCallbacks {
         * Called right before the fragment's {@link Fragme
                                    04-18 08:55:05.501 32141-32141/com.example.jenif.dialogfragment V/com.example.jenif.dialogfragment.dialog&gt;&gt;&gt;: onattach    oncreate    onCreateDialog04-18 08:55:05.529 32141-32141/com.example....
                                    如果我从一个活动启动一个DialogFragment,当我关闭DialogFragment时会发生什么?活动是否通过onResume状态?或者调用是否是正常的java调用,以便在DialogFragment关闭之前永远不会执行下一行?假设启动我的片段的方法是private void launchFragment(){ConfirmationDialog confirm = new Confirma...
                                    Fragment是Activity中的一部分,有自己的生命周期,但是受Activity的生命周期的影响。在onResume()之后,onPause()之前,可以单独操作每个Fragment,比如添加删除它们。在执行Fragment的事务时,可以将事务添加到一个栈中,这个栈被Activity管理,栈中每 一条都是fragment的一次事务,有了这个栈就可以反向的执行Fragment的事务,这样Fra
                                    转载借鉴:https://www.imooc.com/article/21577
1、 Android官方推荐使用DialogFragment创建对话框,在android3.0时被引用。是一种特殊的Fragment,用于在Activity的内容上展示一个对话框。
2、DialogFragment有着Dialog没有的非常好的特性
(1)它本身是Fragment的子类,有着和Fragment基本一样...
                                    点击“奇舞移动技术”关注我们!前言Fragment是在Android 3.0提出的,为了兼容低版本,support-v4库也提供了一套Fragment 的API,这也是官...
                                    随着Fragment这个类的引 入,Google官方推荐大家使用DialogFragment来代替传统的Dialog.1,AlertDialogDialogFragmentbefore:AlertDialog dialog = new AlertDialog.Builder(this)
    .setTitle("Dialog")
    .setMessage("thisis a dialog
了解Dialog生命周期,可以有效解决借助弹窗在执行完整的生命周期过程中,重写其方法执行某些你想达到的操作。
Dialog仅在在第一次启动时候会执行onCreate()方法
之后无论该Dialog执行Dismiss(),cancel(),stop(),D
 DialogFragment是继承Fragment,兼具FragmentDialog的特点:
  一方面,它具有Fragment生命周期,可以由Activity的FragmentManager来管理器生命周期;
  另一方面,其内部包含一个Dialog成员变量,可以像窗口一样展示。
##.DialogFragment相对于Dialog的优点:
 Dialog生命周期不会随着Activity生命周期变化而变化,而DialogFragment继承自Fragme...
显示页面除了Activity,使用最多的可能就是Dialog、PopupWindow、Toast了。这三者有相似之处也有不一样的地方,本篇文章旨在厘清三者关系,阐明各自的优缺点,并探讨哪种场合使用它们。
本篇文章涉及到WindowManager相关知识,如有需要请移步:Window/WindowManager 不可不知之事
通过本篇文章,你将了解到:
1、Dialog/PopupWindow/Toast 生命周期
2、Dialog/PopupWindow/Toast 异同之处
3、Dialog/Po
                                    DialogDialogFragment 都不会出发activity的生命周期变动。 
也就是说,Dialog的show与dismiss不会引发activity的onPause()和onResume的执行。