フラグメント マネージャーの状態ハンドラー

重要

この記事では、パブリック プレビュー段階であり、一般公開前に大幅に変更される可能性がある機能とガイダンスについて説明します。 本書に記載された情報について、Microsoft は明示または黙示を問わずいかなる保証をするものでもありません。

FragmentManagerStateHandler クラスは、画面モードの切り替えが発生したときのフラグメントの復元に役立ちます。

アプリのモードをデュアル スクリーンからシングル スクリーン モードに変えるとき、目に見えなくてもすべてのフラグメントは再作成されます。

このライブラリを使用すると、必要なフラグメントだけが再作成されます。

フラグメントはアクティビティ バンドルから復元されます。 この方法では、スパン モードに応じて、実行時に 2 つのバンドルがスワップされます。 1 つの画面用に 1 つの、スパン モード用にもう 1 つ別のバンドルがあります。 これは、アクティビティ ライフサイクル コールバックを追加し、これら 2 つのバンドルを onActivityPreCreated コールバック内で交換することによってのみ可能です。

コンポーネントにより、画面モードが自動的に検出されます。 画面モードに応じて、必要なフラグメントのみが復元されます。

重要

コンポーネントでは、AndroidX のアクティビティのみが機能します。

使用方法

class SampleApp : Application() {
    override fun onCreate() {
        super.onCreate()
        FragmentManagerStateHandler.init(this)
    }
}
class SampleActivity : AppCompatActivity() {
    companion object {
        private const val FRAGMENT_DUAL_START = "FragmentDualStart"
        private const val FRAGMENT_DUAL_END = "FragmentDualEnd"
        private const val FRAGMENT_SINGLE_SCREEN = "FragmentSingleScreen"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sample)
        registerWindowInfoFlow()
    }

    private fun registerWindowInfoFlow() {
        val windowInfoRepository = windowInfoRepository()
        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                windowInfoRepository.windowLayoutInfo.collectIndexed { index, info ->
                    if (index == 0) {
                        onScreenInfoChanged(info)
                    }
                }
            }
        }
    }

    /**
     * Called whenever the screen info was changed.
     * @param windowLayoutInfo object used to retrieve screen information
     */
    private fun onScreenInfoChanged(windowLayoutInfo: WindowLayoutInfo) {
        when {
            windowLayoutInfo.isInDualMode() -> setupDualScreenFragments()
            else -> setupSingleScreenFragments()
        }
    }

    /**
     * Adds fragments for the single screen mode
     */
    private fun setupSingleScreenFragments() {
        if (supportFragmentManager.findFragmentByTag(FRAGMENT_SINGLE_SCREEN) == null) {
            supportFragmentManager.inTransaction {
                replace(R.id.first_container_id, SingleScreenFragment(), FRAGMENT_SINGLE_SCREEN)
            }
        }
    }

    /**
     * Adds fragments for the dual screen mode
     */
    private fun setupDualScreenFragments() {
        if (supportFragmentManager.findFragmentByTag(FRAGMENT_DUAL_START) == null &&
            supportFragmentManager.findFragmentByTag(FRAGMENT_DUAL_END) == null
        ) {
            supportFragmentManager.inTransaction {
                replace(R.id.first_container_id, DualStartFragment(), FRAGMENT_DUAL_START)
            }

            supportFragmentManager.inTransaction {
                replace(R.id.second_container_id, DualEndFragment(), FRAGMENT_DUAL_END)
            }
        }
    }
}

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
    val fragmentTransaction = beginTransaction()
    fragmentTransaction.func()
    fragmentTransaction.commit()
}

次のステップ

他の「デュアルスクリーンのレイアウト ライブラリ」を確認します。