IllegalStateException: активность была уничтожена - когда приложение пытается показать DialogFragment раз больше времени
Я нашел много подобных вопросов на stackoverflow, но их решения не работают в моем случае. Они связаны с методом onSaveInstanceState
и особенно с библиотекой поддержки.
У меня есть Activity
который работает на одном событии этот код:
MyDialogFragment.showMyDialog(name, this, this);
name
параметром является объект String. Второй параметр (this
) - это объект класса just Activity
, а третий (также this
) - это простой интерфейс. Этот мой Activity
реализует этот интерфейс. showMyDialog()
конечно же статичен метод. Это его тело:
MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
fragment.show(activity.getFragmentManager(), "myDialog");
Это хорошо работает с первой попытки. Но на втором я получаю это исключение:
E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.myapp, PID: 20759
java.lang.IllegalStateException: Activity has been destroyed
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1345)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
at android.app.BackStackRecord.commit(BackStackRecord.java:575)
at android.app.DialogFragment.show(DialogFragment.java:230)
at com.example.myapp.view.dialog.MyDialogFragment.showMyDialog(MyDialogFragment.java:41)
at com.example.myapp.MyActivity.showMyDialog(MyActivity.java:208)
at com.example.myapp.MyActivity.onEvent(MyActivity.java:232)
at com.example.myapp.MyActivity.handleMessage(MyActivity.java:89)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
В общем случае это шаги для воспроизведения моего исключения:
- введите
Activity
- событие получено, так чтоMyDialogFragment
показано. - закрыть диалог с помощью отрицательной кнопки.
- введите
Activity
еще раз -MyDialogFragment
будет показано снова. - введите некоторый код в EditText.
- в этот момент проверка занимает некоторое время. Подключение с сервером и т. д. И возвращается отрицательный результат. Так что нужно еще раз показать
MyDialogFragment
. Но в данный момент я получаю исключение.
Однако, когда я пропущу второй пункт и начну вводить неверный код для проверки, MyDialogFragment
будет показано без каких-либо проблем. Странное поведение.
Я пробовал с нестатическим методом, setRetainInstance(true)
и также commitAllowingStateLoss
. Но разницы не было никакой.
5 ответов:
Это немного странно - или, может быть, просто ошибка в этой функциональности Android. Я добавил блок
try catch
, чтобы поймать исключение броска таким образом:MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name); try { fragment.show(activity.getFragmentManager(), "myDialog"); } catch (Exception e) { e.printStackTrace(); }
И, конечно, исключение все еще бросает (и ловит в этот момент), и что интересно, мой фрагмент диалога воссоздается правильным образом, и пользователь может взаимодействовать с ним.
В методе
showMyDialog()
первая попытка :MyDialogFragment fragment = activity.findFragmentByTag("myDialog");
Если
(fragment == null)
, то инициализируем :MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
Еще покажи:
fragment.show(activity.getFragmentManager(), "myDialog");
Обновление:
void showMyDialog() { MyDialogFragment fragment = activity.getFragmentManager().findFragmentByTag("myDialog"); if (fragment == null) { fragment = new MyDialogFragment(listener, "Hello " + name); } fragment.show(activity.getFragmentManager(), "myDialog"); }
(для API 17 и выше)
В случае, если у кого-то все еще есть эта проблема (или даже связанная с методом транзакции
commit()
), я просто добавил проверку перед ним:private showFragment() { if (isDestroyed()) { return; } // Else do whatever transaction... }
Просто измените нижнюю строку
MyDialogFragment.showMyDialog(name, this, this);
К
MyDialogFragment.showMyDialog(name, **"Activity class name.this"**, this);
У меня была та же ошибка, когда я пытался добавить
SupportMapFragment
вDialogFragment
. Я мог бы исправить эту ошибку, используяgetChildFramentManager()
вместоgetFragmentManager()
, как это предлагает API при использовании вложенных фрагментов:public class GpsDialogFragment extends DialogFragment { private SupportMapFragment mapFragment; private static final String MAP_FRAGMENT_TAG = "MAP_FRAGMENT"; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.gps_postition_dialog, container, false); // ... // dynamically create the map fragment (https://stackoverflow.com/questions/14083950) FragmentManager fragmentManager = getChildFragmentManager(); mapFragment = (SupportMapFragment) fragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG); if (mapFragment == null) { if (!getActivity().isFinishing()) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fragmentManager.beginTransaction(); ft.add(R.id.mapFrame, mapFragment, MAP_FRAGMENT_TAG); ft.commit(); fragmentManager.executePendingTransactions(); } } return view; } // ... @Override public void onPause() { if (mapFragment != null) getChildFragmentManager().beginTransaction().remove(mapFragment).commit(); super.onPause(); } }