Android:为什么 DialogFragment 在方向更改时返回空指针 [英] Android: Why DialogFragment return nullpointer on orientation change

查看:12
本文介绍了Android:为什么 DialogFragment 在方向更改时返回空指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在更改方向后,我遇到了正确对话框片段解散的问题.我猜这是由于旧的上下文,因为在重新创建该活动之后,创建了一个新的活动和相应的上下文.我知道我可以在 onSaveInstance 中设置一些变量来保存对话框状态并在必要时重新创建对话框,或者只是将一个属性放在清单方向"中.但是,也许有更好的方法可以做到不在清单中硬编码它而不是手动保存在 onSaveIntance 中?我也尝试在主片段和对话框片段中使用 setRetainInstance 但它对我没有帮助.

I have a problem with correct dialog fragment dismissing after that orientation was changed. I guess that's due to old context because after that activity was recreated there was created a new activity and corresponding context. I know that I can set some variable in onSaveInstance to save dialog status and recreate dialog if it`s necessary, or just put one attribute in manifest "orientation". But, maybe, there is something better way to do it to not hardcode it in manifest and not save in onSaveIntance manually? I also tried to use setRetainInstance in both main fragment and dialog fragment but it doesn't help me.

片段:

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");
}

LOgCat:

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)

如果我将 setRetainInstance(true) 放在调用 dialogFragment 的主片段中,然后将其放在 onCreate 方法的 DialogFragment 中,那么我会看到 getRetainInstance 返回 true 并且 getDialog 在方向更改过程中具有对象(否则为 NPE).在这种情况下,我也没有 NPE,但是会出现以下奇怪的行为:创建并呈现对话框,重新创建对话框(方向更改)并关闭(为什么?),重新创建对话框(再次更改方向)并呈现(wtf?上次它被解除了)等等,即对话在一侧被解除,但请记住它应该在另一侧呈现.那是什么?

If I put setRetainInstance(true) in main fragment which calls dialogFragment and in DialogFragment in onCreate method only then I see that getRetainInstance return true and getDialog has object in the process of orientation change(otherwise NPE). In this case I also don`t have NPE BUT there will be following strange behaviour: dialog created and presented, dialog recreated(orientation change) and dismissed(why?), dialog recreated(again orientation changed) and presented(wtf? last time it was dismissed) and so on i.e dialog dismissed on one side but remember that on another side it should be presented. What is that?

推荐答案

onCreateDialog(Bundle savedInstanceState) 中移除 setRetainInstance(true); 并保留在 onCreate(捆绑 savedInstance) 如下:

Remove the setRetainInstance(true); from onCreateDialog(Bundle savedInstanceState) and keep it in onCreate(Bundle savedInstance) as follows :

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

这篇关于Android:为什么 DialogFragment 在方向更改时返回空指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆