Поделиться через


Обработчик состояния диспетчера фрагментов

Важно!

В этой статье описаны функциональные возможности общедоступной ознакомительной версии, а также инструкции по ее использованию. Сведения могут быть существенно изменены, прежде чем версия станет общедоступной. Майкрософт не дает никаких гарантий, явных или подразумеваемых, в отношении предоставленной здесь информации.

FragmentManagerStateHandler — это класс, который позволяет реализовать восстановление фрагментов при изменении режима экрана.

Когда мы переводим приложение из режима двойного экрана в режим одинарного, все фрагменты создаются заново, даже если они не видны.

С помощью этой библиотеки будет воссоздан только нужный фрагмент.

Так как фрагменты восстанавливаются из пакета активности, у нас может быть два пакета, которые меняются местами во время выполнения в зависимости от режима растягивания: один пакет для одинарного экрана и другой — для режима растягивания. Это возможно только путем добавления обратного вызова жизненного цикла активности и замены этих двух пакетов в пределах обратного вызова 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()
}