Как правильно вытолкнуть фрагмент после сетевого обратного вызова?
У меня есть фрагмент A, который при нажатии кнопки открывает фрагмент B. Фрагмент B выполняет сетевой вызов и тем временем показывает анимацию пользовательского интерфейса для загрузки (простой загрузчик Lottie Animation). После завершения сетевого вызова фрагмент B извлекается из заднего стека.
Теперь, когда сетевой вызов занимает больше обычного времени (например, 10 секунд) и если пользователь блокирует экран или уходит от приложения (другими словами, вызывается onStop() Activity), когда пользователь возвращается обратно в приложение, он вылетает из-за трассировки стека ниже.
У меня есть хакерское решение для этого, то есть я могу отложить вызов pop с помощью handler.postDelayed(), но я понимаю, что это не изящное решение, и явно что-то здесь делается неправильно. Любая помощь здесь приветствуется.
Fatal Exception: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1776)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1841)
at androidx.fragment.app.FragmentManager.executePendingTransactions(FragmentManager.java:489)
at com.custom.org.core.base.FragNavController.executePendingTransactions(FragNavController.java:657)
at com.custom.org.core.base.FragNavController.popFragments(FragNavController.java:291)
at com.custom.org.core.base.FragNavController.popFragment(FragNavController.java:227)
at com.custom.org.core.base.FragNavController.popFragment(FragNavController.java:234)
at com.custom.org.passive.stepsDonation.ConvertingStepsToCharityFragment.exitConvertingToCharityFragment(ConvertingStepsToCharityFragment.kt:232)
at com.custom.org.passive.stepsDonation.ConvertingStepsToCharityFragment.access$exitConvertingToCharityFragment(ConvertingStepsToCharityFragment.kt:33)
at com.custom.org.passive.stepsDonation.ConvertingStepsToCharityFragment$observeFailureMsgLiveData$1.onChanged(ConvertingStepsToCharityFragment.kt:193)
at com.custom.org.passive.stepsDonation.ConvertingStepsToCharityFragment$observeFailureMsgLiveData$1.onChanged(ConvertingStepsToCharityFragment.kt:33)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:144)
at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:443)
at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:395)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:300)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:339)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:145)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:131)
at androidx.fragment.app.FragmentViewLifecycleOwner.handleLifecycleEvent(FragmentViewLifecycleOwner.java:51)
at androidx.fragment.app.Fragment.performStart(Fragment.java:2737)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:355)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1192)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2617)
at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2575)
at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:258)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:550)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
at com.sharesmile.share.core.MainActivity.onStart(MainActivity.java:330)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
at android.app.Activity.performStart(Activity.java:6994)
at android.app.Activity.performRestart(Activity.java:7131)
at android.app.ActivityThread.handleWindowVisibility(ActivityThread.java:4434)
at android.app.ActivityThread.-wrap33(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6816)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1565)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1453)
Вот как я вытаскиваю фрагмент:
public void popFragments(int popDepth, @Nullable FragNavTransactionOptions transactionOptions) throws UnsupportedOperationException {
if (isRootFragment()) {
throw new UnsupportedOperationException(
"You can not popFragment the rootFragment. If you need to change this fragment, use replaceFragment(fragment)");
} else if (popDepth < 1) {
throw new UnsupportedOperationException("popFragments parameter needs to be greater than 0");
} else if (mSelectedTabIndex == NO_TAB) {
throw new UnsupportedOperationException("You can not pop fragments when no tab is selected");
}
//If our popDepth is big enough that it would just clear the stack, then call that.
if (popDepth >= mFragmentStacks.get(mSelectedTabIndex).size() - 1) {
clearStack(transactionOptions);
return;
}
Fragment fragment;
FragmentTransaction ft = createTransactionWithOptions(transactionOptions);
//Pop the number of the fragments on the stack and remove them from the FragmentManager
for (int i = 0; i < popDepth; i++) {
fragment = mFragmentManager.findFragmentByTag(mFragmentStacks.get(mSelectedTabIndex).pop().getTag());
if (fragment != null) {
ft.remove(fragment);
}
}
//Attempt to reattach previous fragment
fragment = reattachPreviousFragment(ft);
boolean bShouldPush = false;
//If we can't reattach, either pull from the stack, or create a new root fragment
if (fragment != null) {
ft.commitAllowingStateLoss();
} else {
if (!mFragmentStacks.get(mSelectedTabIndex).isEmpty()) {
fragment = mFragmentStacks.get(mSelectedTabIndex).peek();
ft.add(mContainerId, fragment, fragment.getTag());
ft.commitAllowingStateLoss();
} else {
fragment = getRootFragment(mSelectedTabIndex);
ft.add(mContainerId, fragment, generateTag(fragment));
ft.commitAllowingStateLoss();
bShouldPush = true;
}
}
executePendingTransactions();
//Need to have this down here so that that tag has been
// committed to the fragment before we add to the stack
if (bShouldPush) {
mFragmentStacks.get(mSelectedTabIndex).push(fragment);
}
mCurrentFrag = fragment;
if (mTransactionListener != null) {
mTransactionListener.onFragmentTransaction(mCurrentFrag, TransactionType.POP);
}
}