非法状态异常:当应用程序再次尝试显示DialogFragment时,活动已被销毁

12

我在stackoverflow上找到了很多类似的问题,但它们的解决方案在我的情况下不起作用。它们与onSaveInstanceState方法和Support库有关。

我有一个Activity,它在一个事件上运行此代码:

MyDialogFragment.showMyDialog(name, this, this);

name参数是一个字符串对象。第二个参数(this)是Activity类的对象,第三个参数(也是this)是简单的接口。我的Activity实现了这个接口。showMyDialog()是一个静态方法。这是它的主体:

MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
fragment.show(activity.getFragmentManager(), "myDialog");

第一次尝试时运作良好。但第二次出现以下异常:

E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.myapp, PID: 20759
java.lang.IllegalStateException: Activity has been destroyed
        at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1345)
        at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
        at android.app.BackStackRecord.commit(BackStackRecord.java:575)
        at android.app.DialogFragment.show(DialogFragment.java:230)
        at com.example.myapp.view.dialog.MyDialogFragment.showMyDialog(MyDialogFragment.java:41)
        at com.example.myapp.MyActivity.showMyDialog(MyActivity.java:208)
        at com.example.myapp.MyActivity.onEvent(MyActivity.java:232)
        at com.example.myapp.MyActivity.handleMessage(MyActivity.java:89)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)

总的来说,这是重现我的异常的步骤:

  1. 进入Activity - 收到事件,因此显示MyDialogFragment
  2. 通过否定按钮关闭对话框。
  3. 再次进入Activity - 再次显示MyDialogFragment
  4. 在EditText中输入一些代码。
  5. 此时需要进行验证。连接服务器等等。并返回负结果。因此需要再次显示MyDialogFragment。但此时我遇到了异常。

然而,当我跳过第二步,开始输入错误的代码进行验证时,MyDialogFragment会被成功显示。奇怪的行为。

我尝试使用非静态方法、setRetainInstance(true)以及commitAllowingStateLoss。但没有任何改变。


你能发布一下你的对话框的showMyDialog方法吗? - kupsef
@kupsef,我在问题中发布了这个方法的主体。正如您所看到的,这只有两行代码。 - woyaru
如果你使用支持库,必须调用getSupportFragmentManager而不是getFragmentManager。此外,如果你在一个片段内部,你必须使用getChildFragmentManager。 - Mattia Franchetto
@MattiaFranchetto 谢谢你的建议,但我没有使用支持库。 - woyaru
5个回答

8

这似乎有点奇怪,或许只是Android功能上的一个bug。我已添加了代码块try catch来捕获异常,代码如下:

MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
try {
    fragment.show(activity.getFragmentManager(), "myDialog");
} catch (Exception e) {
    e.printStackTrace();
}

当然,异常仍在抛出(并在此时捕获),有趣的是我的对话框片段正在正确地重新创建,并且用户可以与其交互。

我只是想在asyncktask完成后显示一个对话框,但有时候用户在此之前关闭了活动,这段代码解决了这个问题。 - Yayo Arellano

5
在方法 showMyDialog() 中,首先尝试:
MyDialogFragment fragment = activity.findFragmentByTag("myDialog");

如果fragment == null,那么进行初始化:
MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);

否则显示它:
fragment.show(activity.getFragmentManager(), "myDialog");

更新:

void showMyDialog() {
    MyDialogFragment fragment = activity.getFragmentManager().findFragmentByTag("myDialog");
    if (fragment == null) {
        fragment = new MyDialogFragment(listener, "Hello " + name);
    }
    fragment.show(activity.getFragmentManager(), "myDialog");
}

你是指 activity.getFragmentManager().findFragmentByTag("myDialog") 吗? - woyaru
但是很不幸,你的答案在我的情况下不起作用。另外,fragment.show()方法不能在else块中。 - woyaru
是的,我已经按照您更新的方式使用了您的答案。但是它什么也没有改变。 - woyaru

4

(适用于API 17及以上版本)

如果有人仍然遇到这个问题(或者与事务的commit()方法相关),我刚刚在它之前添加了一个检查:

private showFragment() {
    if (isDestroyed()) {
        return;
    }

    // Else do whatever transaction...
}

2

只需要更改下面这一行

MyDialogFragment.showMyDialog(name, this, this);

to

MyDialogFragment.showMyDialog(name, **"Activity class name.this"**, this);

但是 showMyDialog() 方法需要作为第二个参数的 Activity 对象,而不是 String - woyaru
不好意思,你误解了我的意思,你不需要将它转换为字符串。只需将其更改为ActivityName.this即可。 - gandhi

0

我在尝试在DialogFragment中添加SupportMapFragment时遇到了相同的错误。根据API建议,我使用getChildFramentManager()而不是getFragmentManager()来解决这个错误,因为它涉及嵌套片段:

public class GpsDialogFragment extends DialogFragment {
    private SupportMapFragment mapFragment;
    private static final String MAP_FRAGMENT_TAG = "MAP_FRAGMENT";


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.gps_postition_dialog, container, false);
        // ...

        // dynamically create the map fragment (https://dev59.com/Qeo6XIcBkEYKwwoYOR0q)
        FragmentManager fragmentManager = getChildFragmentManager();
        mapFragment = (SupportMapFragment) fragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG);
        if (mapFragment == null) {
            if (!getActivity().isFinishing()) {
                mapFragment = new SupportMapFragment();
                FragmentTransaction ft = fragmentManager.beginTransaction();
                ft.add(R.id.mapFrame, mapFragment, MAP_FRAGMENT_TAG);
                ft.commit();
                fragmentManager.executePendingTransactions();
            }
        }

        return view;
    }

    // ...

    @Override
    public void onPause() {
        if (mapFragment != null)
            getChildFragmentManager().beginTransaction().remove(mapFragment).commit();
        super.onPause();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接