【问题标题】:Android DialogFragment crash on screen rotationAndroid DialogFragment 在屏幕旋转时崩溃
【发布时间】:2014-12-31 20:01:12
【问题描述】:

我有一个 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);
}

【问题讨论】:

  • 发布 logcat 堆栈跟踪
  • 请等一下
  • 更快,除夕不到1h :)
  • 为什么需要 logcat?
  • mTitle、mMessage 和 mListener 为空

标签: android exception android-fragments nullpointerexception dialog


【解决方案1】:

您不能保留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
    }
}

【讨论】:

  • 我在同一个活动中为这个对话框有两个案例,所以我不能只在活动中实现它。
  • @User - 这很容易;只需将活动参数转换为onAttach() 中的DialogListener,将引用存储在实例字段中,并根据需要使用它。
【解决方案2】:

侦听器不应作为参数传入,而应作为接口的一部分在对话框片段本身中实现,并且可能是一个活动。这样,当正面/负面点击发生时,您可以更新某些数据并将其传递给侦听器。监听器,当被activity实现时,会将数据传递给activity,然后你可以在activity中采取相应的行动。

检查这几个例子 - 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

希望对你有帮助。

【讨论】:

  • 我在同一个活动中为这个对话框有两个案例,所以我不能只在活动中实现它。
  • 能否请您多发些代码,以便更好地理解您的调用机制。到目前为止,您还不清楚您要实现的目标。
  • mListener 在屏幕旋转后为空,因此如果我单击对话框中的按钮,它将抛出 NullPointerException。请告诉我哪部分代码对你有帮助。
  • 请发布您的活动代码和对话片段代码。我相信,您的 mListener 正在初始化,但由于旋转被重置为 null 并且片段没有重新附加到存在活动。可以使用 setRetainInstance true 在活动轮换中保留片段,因此即使重新启动活动,片段也只是分离并重新附加
  • 这不是问题。 mFirstListener 和 mSecondListener 是我活动的局部变量。它们在声明中被初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多