Android FragmentManager BackStackRecord.run бросает NullPointerException
Иногда я получаю следующее исключение при работе с фрагментами:
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:591)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Исключение возникает, когда run()
из BackStackRecord
вызывается через execPendingTransactions()
, когда он пытается удалить фрагмент из менеджера.
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim; <----
mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;
Я не могу понять, что именно вызывает это? Я думаю, что это связано с тем, что фрагменты не очищаются сразу после удаления фрагментов.
Ответы
Ответ 1
Отвечая на мой собственный вопрос:
Это исключение (в конце концов) вызывается при вызове FragmentTransaction.remove(null);
и FragmentTransaction.commit();
EDIT: А также, например, Twice Circled и shinyuX указывают в комментарии; при вызове методов show(null)
или add(null)
, attach(null)
и detach(null)
и, возможно, также hide(null)
После вызова commit()
транзакция будет помещена в очередь в FragmentManager. В результате, когда операция обрабатывается после явного вызова FragmentManager.executePendingTransactions()
или когда поток очереди FragmentManager вызывает ее, она выдает NullPointerException
.
В моем случае я поддерживал состояния фрагментов в глобальном объекте. Там я проверил, показывал ли фрагмент или нет, а затем удалял видимые фрагменты. Но поскольку я начал новую FragmentActivity, эти состояния по-прежнему были установлены в true, пока они не были видны. Так что это ошибка дизайна.
Помимо исправления ошибки проектирования, решение было простым: проверьте, вернул ли FragmentManager.findFragmentByTag()
null
, прежде чем удалять фрагмент.
Ответ 2
Я не использую тег для создания фрагментов (они работают как контейнеры TabBar).
Итак, он работает при изменении вкладки, но если я нажму кнопку "Назад", я получаю ту же ошибку.
В методе onDestroyView я нашел экземпляр фрагмента с FragmentManager # findFragmentById, однако FragmentManager # findFragmentByTag возвращает null, конечно.
class MyFragment extends ListFragment {
@Override
public void onDestroyView() {
super.onDestroyView();
if (this.mapFragment != null
&& getFragmentManager().findFragmentById(
this.mapFragment.getId()) != null) {
getFragmentManager().beginTransaction().remove(this.mapFragment)
.commit();
this.mapFragment = null;
}
}
}