Ошибка DialogFragment.dismiss с использованием NullPointerException
Я делаю некоторые фоновые работы и показывая DialogFragment, пока я это делаю. Как только моя работа будет выполнена, и соответствующий ответ будет вызван, я отклоню диалог. Когда я это делаю, я получаю сбой, вызванный NPE в источнике Android, здесь:
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();
Ответы
Ответ 1
Это может также произойти, когда вы вызываете функцию увольнения(), прежде чем вы вызываете show(), как сказал Соггер.
После создания объекта 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() может быть достаточно...
Ответ 2
Самое простое решение - проверить "getFragmentManager()" на "null" перед вызовом метода "Отклонить()". Также вы можете расширить класс "DialogFragment" и переопределить метод "Отклонить()", чтобы проверить его там:
@Override
public void dismiss()
{
if (getFragmentManager() != null) super.dismiss();
}
Ответ 3
Я знаю, что это сообщение устарело, но я столкнулся с аналогичным случаем, который мне нужно решить без рефакторинга или изменения большого количества кода. Надеюсь, это полезно для кого-то.
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 "safer" to dismiss
shouldDismiss = false;
super.dismiss();
} else {
shouldDismiss = true;
allowStateLoss = false;
}
}
@Override
public void dismissAllowingStateLoss() {
if (getActivity() != null) { // it "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);
}
}
Ответ 4
Моя ставка будет заключаться в том, что код, который вы отправили, из фонового потока... вам не разрешено обновлять пользовательский интерфейс из любого другого места, кроме потока пользовательского интерфейса.
Вы можете использовать onPostExecute() или runOnUiThread() для достижения своей цели (если моя догадка правильна о том, что происходит)
Ответ 5
Проверка наличия видимости перед сглаживанием может исключить это исключение нулевого указателя
if (mDialog != null && mDialog.isVisible) {
mDialog.dismiss();
mDialog = null;
}
Ответ 6
Обратный вызов, который вызывается, вероятно, относится к активности, которая или должна быть уничтожена (после изменения ориентации), также может быть создан диалог выполнения с тем же самым действием. Это может вызвать 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();
}