web-dev-qa-db-ja.com

バックスタック管理:リスターターは所有者の初期化段階でのみ作成する必要があります

MainActivityの下部ナビゲーションバーを使用して、いくつかのフラグメントを処理しています。これは、それらを切り替えるために使用されるコードです。

private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
    if (item.isChecked &&
        supportFragmentManager.findFragmentById(R.id.act_main_fragment_container) != null
    )
        return@OnNavigationItemSelectedListener false
    val fragment =
        when (item.itemId) {
            R.id.navigation_home      -> fragments[0]
            R.id.navigation_bookings  -> fragments[1]
            R.id.navigation_messages  -> fragments[2]
            R.id.navigation_dashboard -> fragments[3]
            R.id.navigation_profile   -> fragments[4]
            else                      -> fragments[0]
        }
    this replaceWithNoBackStack fragment
    return@OnNavigationItemSelectedListener true
}

メソッドreplaceWithNoBackstackは、これの省略形にすぎません。

supportFragmentManager
    ?.beginTransaction()
    ?.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
    ?.replace(containerId, fragment)
    ?.commit()

問題は、それらをすばやく切り替えると、次の例外でアプリがクラッシュすることです。

Java.lang.IllegalStateException:スターターは、androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.Java:59)at androidx.fragment.app.Fragment.performCreate(Fragment.Java:2580)at androidx。 fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.Java:837)at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.Java:1237)at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.Java:1302) .fragment.app.BackStackRecord.executeOps(BackStackRecord.Java:439)at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.Java:2075)at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.Java:1865)at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManaのandroidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.Java:1820) gerImpl.Java:1726)、androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.Java:150)at Android.os.Handler.handleCallback(Handler.Java:789)at Android.os.Handler.dispatchMessage(Handler。 Java:98)at Android.os.Looper.loop(Looper.Java:164)at Android.app.ActivityThread.main(ActivityThread.Java:6709)at Java.lang.reflect.Method.invoke(Native Method)at com .Android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.Java:240)at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:769)たくさん検索していて、見つからなかった答え。

API呼び出しを行ってアプリをバックグラウンドに置き、応答を待つ場合にもこのエラーが発生しました。アプリに戻ると、ダイアログフラグメントをすぐに表示しようとしているため、アプリがクラッシュします(理由これは、ダイアログフラグメントの表示時に、バックグラウンドから戻ったときにフラグメントを再作成するトランザクションがまだ進行中であると考えられます)。他の解決策を理解できなかったため、ダイアログに500ミリ秒の遅延を設定することで、これを手っ取り早い方法で解決しました。

詳細については、お問い合わせください。前もって感謝します!

可能な一時的な解決策

[〜#〜] edit [〜#〜]アプリの互換性の依存関係をandroidx.appcompat:appcompat:1.0.2にダウングレードすることでこの問題を解決しましたが、これは一時的な解決策です。未来。私は誰かがそれを理解することを望んでいます。

編集2フラグメントトランザクションからsetTransition()を削除して問題を解決しました。少なくとも、私はAndroidアプリに一般的に適切な移行がない理由を知っています

編集この問題を回避し、物事を円滑に進めるためのおそらく最良の解決策は、ViewPagerを使用してボトムバーのナビゲーションを処理することです

19
Gabi

Drown Coder's ソリューション以外は何も機能しませんでしたが、トランザクションをバックスタックに追加するため、完全ではありませんでした。したがって、下部ナビゲーションのすべてのボタンを押すと、バックスタックにすべてのフラグメントが少なくとも1つあります。このソリューションを少し改善したので、アクションアニメーションよりもアプリをクラッシュさせる.replace()を使用しないでください。

これがコードです:

if (getChildFragmentManager().getBackStackEntryCount() > 0) {
    getChildFragmentManager().popBackStack();
}

FragmentTransaction addTransaction = getChildFragmentManager().beginTransaction();
addTransaction.setCustomAnimations(R.animator.fragment_fade_in, R.animator.fragment_fade_out);
addTransaction.addToBackStack(null);
addTransaction.add(R.id.frame, fragment, fragment.getClass().getName()).commitAllowingStateLoss();
0

setCustomAnimationsを使用すると、この問題が発生します。 setCustomAnimationsを削除することで私の問題は解決しました。また、フラグメントの新しいインスタンスを作成してから、setCustomAnimationを使用して表示する場合でも問題ありません。

編集:別の方法は、フラグメントをバックスタックに追加することです。

0
Hadi Ahmadi