Навигация без создания нового экземпляра фрагмента - компонент навигации

Можно ли использовать navigate функция из Android Navigation Component без создания нового экземпляра фрагмента, но как восстановить предыдущий?

Я пытался восстановить предыдущий фрагмент, но только с использованием navigate Данные функции могут передаваться между фрагментами.

3 ответа

Пока нет, но я думаю, они над этим работают. На данный момент всегда создается новый экземпляр. Но если написать собственный навигатор, это возможно.

@Navigator.Name("keep_state_fragment") // `keep_state_fragment` is used in navigation xml
class KeepStateNavigator(
    private val context: Context,
    private val manager: FragmentManager, // Should pass childFragmentManager.
    private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {

    override fun navigate(
        destination: Destination,
        args: Bundle?,
        navOptions: NavOptions?,
        navigatorExtras: Navigator.Extras?
    ): NavDestination? {
        val tag = destination.id.toString()
        val transaction = manager.beginTransaction()

        var initialNavigate = false
        val currentFragment = manager.primaryNavigationFragment
        if (currentFragment != null) {
            transaction.detach(currentFragment)
        } else {
            initialNavigate = true
        }

        var fragment = manager.findFragmentByTag(tag)
        if (fragment == null) {
            val className = destination.className
            fragment = manager.fragmentFactory.instantiate(context.classLoader, className)
            transaction.add(containerId, fragment, tag)
        } else {
            transaction.attach(fragment)
        }

        transaction.setPrimaryNavigationFragment(fragment)
        transaction.setReorderingAllowed(true)
        transaction.commitNow()

        return if (initialNavigate) {
            destination
        } else {
            null
        }
    }
}

Тогда вы должны позвонить, как показано ниже

val navigator = KeepStateNavigator(this, navHostFragment.childFragmentManager, R.id.nav_host_fragment)
        navController.navigatorProvider.addProvider(navigator)

Это образец: Github

Я улучшил ответ Умута АДАЛИ:

      /**
 * Created by Nooi on 12,February,2021
 */
@Navigator.Name("fragment")
class PersistentFragmentNavigator(
    persistentClasses : Set<KClass<out Fragment>>,
    context : Context,
    manager : FragmentManager,
    containerId : Int
) : FragmentNavigator(context, manager, containerId) {

    private val navigatorHandler = PersistentNavigatorHandler(persistentClasses, manager, containerId)

    init {
        navigatorHandler.addTopFragmentIfRequired()
    }

    override fun instantiateFragment(context : Context, fragmentManager : FragmentManager, className : String, args : Bundle?) : Fragment {
        return navigatorHandler.instantiateFragment(className) {
            super.instantiateFragment(context, fragmentManager, className, args)
        }
    }
}

private class PersistentNavigatorHandler(
    private val persistentClasses : Set<KClass<out Fragment>>,
    private val manager : FragmentManager,
    private val containerId : Int
) {

    private val instances = mutableMapOf<String, Fragment>()

    fun addTopFragmentIfRequired() {
        manager.findFragmentById(containerId)
            ?.takeIf { fragment ->
                persistentClasses.any { it.qualifiedName == fragment.javaClass.name }
            }
            ?.let { fragment ->
                instances[fragment.javaClass.name] = fragment
            }
    }

    fun instantiateFragment(className : String, superCall : () -> Fragment) : Fragment {
        return instances[className] ?: superCall.invoke().also { fragment ->
            if (persistentClasses.any { it.qualifiedName == className }) {
                instances[className] = fragment
            }
        }
    }
}

Добавьте этот код в свою активность onCreate сразу после получения navController и navHostFragment:

          navController.navigatorProvider.addNavigator(PersistentFragmentNavigator(
        persistentClasses = setOf(SomePersistentFragment::class),
        context = this,
        manager = navHostFragment.childFragmentManager,
        containerId = R.id.nav_host_fragment
    ))

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

Я считаю, что вы можете получить модели просмотра ViewModelProvider из активности.

inline fun <reified VM : ViewModel> BaseFragment.vmProviderActivity() = lazy {

    val viewModel = activity?.let { ViewModelProviders.of(it).get(VM::class.java) }

    if (viewModel is BaseViewModel) {
        viewModel.kodeinInstance = kodein
    }

    return@lazy viewModel
}
Другие вопросы по тегам