[关闭]
@946898963 2020-06-11T17:58:55.000000Z 字数 2062 阅读 1676

DialogFragment show 问题

Android学习笔记


自我感觉DialogFragment似乎没有那么好用,主要就是show的时候需要传递FragmentManager(),这就需要调用getSupportFragmentManager()方法,而这个方法需要传递上下文才能获取,有些场景下上下文不好传递进去,所以这种场景下反而不如Dialog或者Dialog类型的Activity好用。

DialogFragment 是系统提供的一种特殊Fragment,通过调用show()方法即可展示Dialog,使用中也需要注意一点。比如,通常触发场景是,用户点击某个按钮,弹出 Dialog。如果你是这么写的话:

  1. if (mDialogFragment == null) {
  2. mDialogFragment = SampleDialogFragment.newInstance();
  3. }
  4. mDialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_SAMPLE);
  5. }

可以看到,为了避免重复创建对象,对DialogFragment做了判空处理。这种写法本身没有错,但如果用户连续点击按钮,导致同一时刻多次触发show操作,你会发现,App立马崩溃退出,并在logcat 提示如下错误信息:

  1. java.lang.IllegalStateException: Fragment already added: a{8fd950d #0 XXXDialogFragment}
  2. at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1361)
  3. at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:734)
  4. at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
  5. at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:536)
  6. at android.os.Handler.handleCallback(Handler.java:739)
  7. at android.os.Handler.dispatchMessage(Handler.java:95)
  8. at android.os.Looper.loop(Looper.java:135)
  9. at android.app.ActivityThread.main(ActivityThread.java:5669)
  10. at java.lang.reflect.Method.invoke(Native Method)
  11. at java.lang.reflect.Method.invoke(Method.java:372)
  12. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)
  13. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

错误信息间接指向show()方法,因为该方法内部调用fragment的add()方法。如果有间隔地点次点击按钮触发show()方法,就不会发生这个问题。这是为什么呢?仔细看看show()方法的注释,里面有这么一段内容:

  1. This does not add the transaction to the back stack. When the fragment is dismissed, a new transaction will be executed to remove it from the activity.

这也就解释了为什么间隔点击不会报错的原因。除了第一次触发,间隔触发时前面一定调用过dismiss() 方法 (dialog 消失),也就是 remove 过 fragment 对象。而连续多次触发时,导致对同一个 fragment 对象多次执行 add 操作,导致报错。知道原因后,解决方案也就有啦。
我们可以对按钮做点击排重处理,更简单点处理就是直接在 show() 之间添加判断,代码如下:

  1. if (mDialogFragment == null) {
  2. mDialogFragment = SampleDialogFragment.newInstance();
  3. }
  4. Dialog mDialog = SampleDialogFragment.getDialog();
  5. if (mDialog==null || !mDialog.isShowing()) {
  6. mDialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_SAMPLE);
  7. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注