Android DialogFragment在屏幕旋转时崩溃

时间:2014-12-31 20:01:13

标签: android exception android-fragments nullpointerexception dialog

我有一个DialogFragment类。我必须在每次显示时设置监听器(我的应用程序中有多个案例)。

但是当我旋转屏幕时,mListener变为null,当我点击一个按钮时会出现NullPointerExcpetion。我无法在活动中实现监听器,因为它有一些用于此对话框的情况,每个都有不同的操作。

CustomDialog类:

MyDialogListener mListener;

public void show(FragmentManager fm, MyDialogListener listener) {
    mListener = listener;
    super.show(fm, "MyDialog");
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new AlertDialog.Builder(getActivity())
            .setTitle("Title")
            .setPositiveButton(android.R.string.ok, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int whichButton) {
                    mListener.onDialogPositiveClick();
                    // NullPointerException after a screen rotate
                }
            })
            .setNegativeButton(android.R.string.cancel, null)
            .create();
}

活动类:

public void showMyFirstDialog() {
    new CutsomDialog().show(getFragmentManager(), mFirstListener);
}

public void showMySecondDialog() {
    new CutsomDialog().show(getFragmentManager(), mSecondListener);
}

2 个答案:

答案 0 :(得分:3)

您无法保留Fragment的实例字段(包括DialogFragment)。使本地数据在配置更改后仍然存在的机制是将片段的参数设置为包含数据的Bundle;此捆绑包将在配置更改后继续存在。

首先,消除show()方法;这不是正确的做法。相反,你可以做这样的事情:

DialogFragment frag = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("TITLE", "Dialog Title Goes Here");
args.putString("MESSAGE", "This is a dialog messaage");
frag.setArguments(args);

frag.show();

然后,您可以在创建AlertDialog

时检索标题和消息
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Bundle args = getArguments();
    String title = args.getString("TITLE");
    String message = args.getString("MESSAGE");

    // set up and return the alert dialog as before
}

处理DialogListener稍微复杂一些。您不希望在配置更改中持有对该引用的引用,因为它将返回到已销毁的活动。相反,您可以安排从片段onAttach()方法中的活动中检索侦听器:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    // now cast activity to your activity class and get a reference
    // to the listener
}

您可能需要稍微更改一下活动类才能使其正常工作。如果您正在使用来自许多活动的此对话框片段,则此处定义活动可以实现的请求监听器的接口特别有用。它看起来像这样:

public interface DialogListenerProvider {
    DialogListener getDialogListener();
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (activity instanceof DialogListenerProvider) {
        mListener = ((DialogListenerProvider) activity).getDialogListener();
    } else {
        // throw an error
    }
}

答案 1 :(得分:1)

不应将侦听器作为参数传入,而是在dialogfragment本身内作为接口的一部分实现,并且可以是一个活动。这样,当正/负点击发生时,您可以更新某些内容的数据并将其传递给侦听器。监听器在通过活动实现时会将数据传递给teh活动,然后您可以在活动中执行相应的操作。

检查以下几个例子 - http://www.i-programmer.info/programming/android/7426-android-adventures-custom-dialogs-using-dialogfragment.html?start=2

http://android-developers.blogspot.com/2012/05/using-dialogfragments.html

希望它有所帮助。