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