当前位置: 首页 > 知识库问答 >
问题:

Android:为什么DialogFragment在方向改变时返回nullpointer

仲孙默
2023-03-14

我有一个问题,正确的对话片段删除后,方向被改变。我想这是由于旧的上下文,因为在该活动被重新创建后,会创建一个新的活动和相应的上下文。我知道我可以在onSaveInstance中设置一些变量来保存对话框状态,如果必要的话重新创建对话框,或者只在清单“定向”中放置一个属性。但是,也许有更好的方法来做到这一点,不在manifest中硬编码,也不在onSaveIntance中手动保存?我还尝试在main片段和dialog片段中使用SetRetaInstane,但这对我没有帮助。

片段:

public class MainFragment extends Fragment implements ServiceExecutorListener, OnClickListener, DialogClickListener {

private static final String TAG = MainFragment.class.getName();

private TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialogFragment pd;
private Button btnSend, btnCheck;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate");
    setRetainInstance(true);
    intent = new Intent(getActivity(), RESTService.class);
    getActivity().startService(intent);
    sConn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            Log.d(TAG, "MainFragment onServiceConnected");
            service = ((RESTService.MyBinder) binder).getService();
            service.registerListener(MainFragment.this);
            if (service.tasksAreDone())
                serviceStatus.setText(service.getResult());
            bound = true;
        }

        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "MainFragment onServiceDisconnected");
            bound = false;
        }

    };
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.main_fragment, container, false);
    serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
    btnSend = (Button) rootView.findViewById(R.id.btnSend);
    btnCheck = (Button) rootView.findViewById(R.id.btnCheck);

    btnSend.setOnClickListener(this);
    btnCheck.setOnClickListener(this);
    return rootView;
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btnSend:
            pd = new ProgressDialogFragment();
            pd.newInstance(null);
            pd.setDialogClickListener(this);
            pd.show(getActivity().getSupportFragmentManager(), "ProgressDialog");
            service.run(RESTService.REQUEST, 7);
            service.run(RESTService.REQUEST, 2);
            service.run(RESTService.REQUEST, 4);
            break;
        case R.id.btnCheck:
            if (service != null)
                serviceStatus.setText(String.valueOf(service.tasksAreDone()) + service.getTasksCount());
            break;
    }
}

@Override
public void onStart() {
    super.onStart();
    Log.d(TAG, "onStart: Bind service");
    getActivity().bindService(intent, sConn, 0);
}

@Override
public void onPause() {
    super.onPause();
    Log.d(TAG, "onPause: Unbind service");
    if (!bound)
        return;
    getActivity().unbindService(sConn);
    service.unregisterListener();
    bound = false;
}

@Override
public void onComplete(int taskID, int action, String result) {
    Log.d(TAG, "Task #" + taskID + ", action = " + action + " Completed");
    pd.dismiss();
    serviceStatus.setText(result);
}

@Override
public void onDialogClick(int action) {
    switch (action) {
        case Dialog.BUTTON_POSITIVE:
            Log.d(TAG, "POSITIVE BUTTON");
            break;
        case Dialog.BUTTON_NEGATIVE:
            Log.d(TAG, "NEGATIVE BUTTON");
            service.removeTasks();
            break;
        case Dialog.BUTTON_NEUTRAL:
            Log.d(TAG, "NEUTRAL BUTTON");
            break;
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy");
}
}
public class ProgressDialogFragment extends DialogFragment implements OnClickListener {

final String TAG = ProgressDialogFragment.class.getName();
private DialogClickListener listener;

public ProgressDialogFragment newInstance(Bundle args) {
    ProgressDialogFragment pdf = new ProgressDialogFragment();
    pdf.setArguments(args);
    return pdf;
}

public void setDialogClickListener(DialogClickListener listener) {
    this.listener = listener;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    Log.d(TAG, "onCreate");
}

public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
            .setTitle("Title!")
            .setPositiveButton(R.string.yes, this)
            .setNegativeButton(R.string.no, this)
            .setNeutralButton(R.string.maybe, this)
            .setCancelable(false)
            .setMessage(R.string.message_text)
            .setOnKeyListener(new OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    return true;
                }
            });
    return adb.create();
}

public void onClick(DialogInterface dialog, int which) {
    if (listener != null)
        listener.onDialogClick(which);
}

public void onDismiss(DialogInterface dialog) {
    Log.d(TAG, "Dialog: onDismiss, dialog = " + getDialog() + ", retainInstance = " + getRetainInstance());
    // Fix to avoid simple dialog dismiss in orientation change
    if ((getDialog() != null) && getRetainInstance())  
        getDialog().setDismissMessage(null);

}

public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);
    Log.d(TAG, "Dialog: onCancel");
}
04-29 06:17:17.860: E/AndroidRuntime(4202): FATAL EXCEPTION: main
04-29 06:17:17.860: E/AndroidRuntime(4202): java.lang.NullPointerException
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.support.v4.app.DialogFragment.dismissInternal(DialogFragment.java:184)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.support.v4.app.DialogFragment.dismiss(DialogFragment.java:155)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at com.example.restservice.fragments.MainFragment.onComplete(MainFragment.java:108)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at com.example.restservice.service.RESTService$1.run(RESTService.java:79)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.os.Handler.handleCallback(Handler.java:605)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.os.Handler.dispatchMessage(Handler.java:92)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.os.Looper.loop(Looper.java:137)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at android.app.ActivityThread.main(ActivityThread.java:4514)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at java.lang.reflect.Method.invokeNative(Native Method)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at java.lang.reflect.Method.invoke(Method.java:511)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
04-29 06:17:17.860: E/AndroidRuntime(4202):     at dalvik.system.NativeStart.main(Native Method)

编辑:

如果我把setRetaInstance(true)放在main fragment中,它调用dialogFragment,而把dialogFragment放在onCreate方法中,那么我会看到getRetaInstance返回true,并且getDialog在方向改变的过程中有对象(否则是NPE)。在这种情况下,我也没有NPE,但会有以下奇怪的行为:对话框创建和呈现,对话框重新创建(方向改变)和取消(为什么?),对话框重新创建(方向再次改变)和呈现(wtf?上次它被取消了)等等,即对话框在一边被取消,但记住在另一边它应该被提出。那是什么?

共有1个答案

曾丰茂
2023-03-14

oncreateDialog(Bundle savedInstanceState)中移除setrateInstance(true);并将其保留在onCreate(Bundle savedInstance)中,如下所示:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}
 类似资料:
  • 下面是一个简单对话框的示例代码: 下面是一些活动代码: 代码与您所看到的引用大致相同。问题是,一旦您改变了方向,当显示对话框时,它就停止了预期的工作-->由于活动生命周期的原因,活动和对话框都被重新构建,并且对话框现在没有对重新构建的新活动的正确引用。 致以最诚挚的问候

  • 问题内容: 我有一个简单的Java类,如下所示: 这段代码的输出是这样的: 为什么s不在finally块中覆盖,而是控制打印输出? 问题答案: 在与所述的执行块完成语句和的值在时间语句执行是由该方法返回的值。finally子句稍后s(在语句完成之后)更改值的事实(此时)并未更改返回值。 请注意,以上内容处理的s是对块中自身值的更改,而不是对s引用对象的更改。如果s是对可变对象的引用(String不

  • 在我开始之前,我读过类似的文章,但它们对我不起作用。 正如我在标题中解释的那样,当我单击肯定按钮(在这种情况下为“确定”)时,我会得到一个NPE。如果有人能指出我做得不正确,那就太好了!下面是我的设置的抽象版本

  • 我正在开发一个应用程序来显示一个频道的直播流,它在默认情况下以景观模式启动,我可以从我的选项菜单中将它改为肖像,反之亦然 现在我在manifest中使用这段代码,并将其放在活动android:configchanges=“keyboardkeyboardhiddenorientationscreensize” 当我启动应用程序,它的工作很好,但当我改变方向为肖像,应用程序是悬挂和选项菜单没有消失,

  • 在我的应用程序中,我已经授予了的权限,并且它正在顺利地检测接收/offhook/idle统计信息。 更新 这是Logcat错误: 04-26 04:55:04.422 140 6-2091/?W/Audio_HW_Generic:没有向哈尔提供足够的数据,预期位置为1097356,只写了1097280 04-26 04:55:04.434 506 5-5065/?d/AndroidRuntime:

  • 问题内容: 在下面的代码中,如果字符串在方法调用之前出现,为什么方法在字符串之前输出?为什么它会跳出输出方法的第一部分的形式,然后离开方法以输出字符串,然后返回到方法以输出方法的返回值? 码: 输出: 问题答案: 首先要注意的是,当对两个操作数使用a时,两个操作数之一是a ,表达式的结果是a 。 因此,在以下方法中调用表达式 您正在调用,因为它是type的变量。注意该方法如何接受单个参数。因此,