DialogFragment.dismiss与NullPointerException崩溃

时间:2012-05-10 02:22:44

标签: android android-fragments

我正在做一些后台工作并在我这样做时显示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();

6 个答案:

答案 0 :(得分:14)

如果您在调用show()之前调用dismiss(),也可能会出现这种情况,如Sogger所说。

在构造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()条件可能就够了......

答案 1 :(得分:10)

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

@Override
public void dismiss()
{
    if (getFragmentManager() != null) super.dismiss();
}

答案 2 :(得分:6)

我知道这条消息已经过时了,但我遇到了类似的情况,我需要解决这个问题而不需要重构或更改大量代码。希望它对某些人有用

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

答案 3 :(得分:5)

我敢打赌,您发布的代码来自后台线程......您不能从UI线程以外的任何位置更新UI。

你可以使用onPostExecute()或runOnUiThread()来实现你的目标(如果我的猜测是正确的)

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

调用的回调可能是在应该销毁的活动上(在方向改变之后),也可能已经使用相同的活动实例化了进度对话框。这可能会导致NPE。 不应从后台任务调用活动回调,以防止出现这类问题。 将后台任务与活动分离,例如使用otto,或阻止后台任务调用(将被)销毁的活动。

这是我的一些代码:

静态内部活动类:

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

}

活动中的奥托订阅:

@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():

        mProgressDialog = (ProgressDialogFragment) getFragmentManager().findFragmentByTag(TAG_PROGRESS_DIALOG);
    if (mProgressDialog == null) {
        mProgressDialog = new ProgressDialogFragment();
    }