24

我正在做一些背景工作并在我这样做的同时显示一个 DialogFragment。一旦我的工作完成并调用了相关的回调,我就会关闭对话框。当我这样做时,我在 android 源代码中遇到了由 NPE 引起的崩溃,这里:

void dismissInternal(boolean allowStateLoss) {
        if (mDialog != null) {
            mDialog.dismiss();
            mDialog = null;
        }
        mRemoved = true;
        if (mBackStackId >= 0) {
            getFragmentManager().popBackStack(mBackStackId,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
            mBackStackId = -1;
        } else {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.remove(this);
            if (allowStateLoss) {
                ft.commitAllowingStateLoss();
            } else {
                ft.commit();
            }
        }
    }

特别是在这一行:FragmentTransaction ft = getFragmentManager().beginTransaction();

4

6 回答 6

15

当您像 Sogger 所说的那样在调用 show() 之前调用 dismiss() 时,也可能会发生这种情况。

Dialog对象构造完成后,dialog不显示前,如果(mDialog != null)可以传入,会发生NullPointerException。

当您检查 mDialog 是否为空时,

if (mDialog != null) {
    mDialog.dismiss();
    mDialog = null;
}

添加更多条件,如下所示,

if ((mDialog != null) && mDialog.isAdded() && mDialog.isResumed()) {
    mDialog.dismiss();
    mDialog = null;
}

我认为 mDialog.isAdded() 条件可能就足够了......

于 2013-05-02T08:34:00.753 回答
11

最简单的解决方案是在调用“dismiss()”方法之前检查“getFragmentManager()”是否为“null”。您也可以扩展“DialogFragment”类并覆盖方法“dismiss()”以在那里检查它:

@Override
public void dismiss()
{
    if (getFragmentManager() != null) super.dismiss();
}
于 2013-11-14T14:55:03.200 回答
7

我知道这条消息很旧,但我遇到了类似的情况,我需要在不重构或更改大量代码的情况下解决。希望它对某人有用

   package com.example.playback;

import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SaferDialogFragment extends DialogFragment {

    private boolean allowStateLoss = false;
    private boolean shouldDismiss = false;

    public SaferDialogFragment() {
    }

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

    @Override
    public void onStart() {
        super.onStart();
        //check if we should dismiss the dialog after rotation
        if (shouldDismiss) {
            if (allowStateLoss)
                dismissAllowingStateLoss();
            else
                dismiss();
        }
    }

    @Override
    public void dismiss() {
        if (getActivity() != null) { // it's "safer" to dismiss
            shouldDismiss = false;
            super.dismiss();
        } else {
            shouldDismiss = true;
            allowStateLoss = false;
        }
    }

    @Override
    public void dismissAllowingStateLoss() {
        if (getActivity() != null) { // it's "safer" to dismiss
            shouldDismiss = false;
            super.dismissAllowingStateLoss();
        } else
            allowStateLoss = shouldDismiss = true;
    }

    //keeping dialog after rotation
    @Override
    public void onDestroyView() {
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);
        super.onDestroyView();
    }



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        /** omitted code **/
        return super.onCreateView(inflater, container, savedInstanceState);
    }
}
于 2014-04-23T18:08:02.800 回答
5

我敢打赌,您发布的代码来自后台线程……您不得从 UI 线程以外的任何地方更新 UI。

您可以使用 onPostExecute() 或 runOnUiThread() 来实现您的目标(如果我对正在发生的事情的猜测是正确的)

于 2012-05-10T03:07:44.683 回答
1

The callback which is invoked is probably on the activity which is or should be destroyed (after orientation change), also the progress dialog might have been instantiated with that same activity. This might cause the NPE. Callbacks on activities should not be invoked from background tasks, to prevent these kinds of problems. Decouple the background task from the activity, for example using otto, or prevent the background task from invoking the (to be) destroyed activity.

This is some code of mine:

static inner class of activity:

    public static class ProgressDialogFragment extends DialogFragment {
    ProgressDialog dialog;

    public ProgressDialogFragment() {
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        dialog = new ProgressDialog(getActivity(), getTheme());
        dialog.setTitle(getString(R.string.please_wait));
        dialog.setMessage(getString(R.string.uploading_picture));
        dialog.setIndeterminate(true);
        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        return dialog;
    }

}

Otto subscription in activity:

@Subscribe
public void onUploadEvent(UploadAvatarEvent uploadAvatarEvent) {
    switch (uploadAvatarEvent.state) {
        case UploadAvatarEvent.STATE_UPLOADING:
            if (!mProgressDialog.isAdded()) {
                mProgressDialog.show(getFragmentManager(), TAG_PROGRESS_DIALOG);
            }
            break;
        case UploadAvatarEvent.STATE_UPLOAD_SUCCES:
            mProgressDialog.dismiss();
            break;
        case UploadAvatarEvent.STATE_UPLOAD_ERROR:
            mProgressDialog.dismiss();
            break;
    }
}

onCreate() in activity:

        mProgressDialog = (ProgressDialogFragment) getFragmentManager().findFragmentByTag(TAG_PROGRESS_DIALOG);
    if (mProgressDialog == null) {
        mProgressDialog = new ProgressDialogFragment();
    }
于 2015-03-05T20:56:25.463 回答
1

在关闭之前检查它是否可见可以避免这个空指针异常

    if (mDialog != null && mDialog.isVisible) {
        mDialog.dismiss();
        mDialog = null;
    }
于 2013-10-16T15:30:10.577 回答