如何在来回导航时防止碎片重新生成?

时间:2019-09-29 09:10:24

标签: android android-fragments

我在活动内部设置了一组片段导航。当我调用findFragmentByTag()时,片段onCreateView()和onViewCreated()再次被调用,数据重置为正常。如何防止碎片重新产生?

1 个答案:

答案 0 :(得分:0)

您可以查看android示例中高级导航的代码

fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent): LiveData<NavController> {

// Map of tags
val graphIdToTagMap = SparseArray<String>()
// Result. Mutable live data with the selected controlled
val selectedNavController = MutableLiveData<NavController>()

var firstFragmentGraphId = 0

// First create a NavHostFragment for each NavGraph ID
navGraphIds.forEachIndexed { index, navGraphId ->
    val fragmentTag = getFragmentTag(index)

    // Find or create the Navigation host fragment
    val navHostFragment = obtainNavHostFragment(
        fragmentManager,
        fragmentTag,
        navGraphId,
        containerId
    )

    // Obtain its id
    val graphId = navHostFragment.navController.graph.id

    if (index == 0) {
        firstFragmentGraphId = graphId
    }

    // Save to the map
    graphIdToTagMap[graphId] = fragmentTag

    // Attach or detach nav host fragment depending on whether it's the selected item.
    if (this.selectedItemId == graphId) {
        // Update livedata with the selected graph
        selectedNavController.value = navHostFragment.navController
        attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
    } else {
        detachNavHostFragment(fragmentManager, navHostFragment)
    }
}

// Now connect selecting an item with swapping Fragments
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag

// When a navigation item is selected
setOnNavigationItemSelectedListener { item ->
    // Don't do anything if the state is state has already been saved.
    if (fragmentManager.isStateSaved) {
        false
    } else {
        val newlySelectedItemTag = graphIdToTagMap[item.itemId]
        if (selectedItemTag != newlySelectedItemTag) {
            // Pop everything above the first fragment (the "fixed start destination")
            fragmentManager.popBackStack(firstFragmentTag,
                FragmentManager.POP_BACK_STACK_INCLUSIVE)
            val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
                as NavHostFragment

            // Exclude the first fragment tag because it's always in the back stack.
            if (firstFragmentTag != newlySelectedItemTag) {
                // Commit a transaction that cleans the back stack and adds the first fragment
                // to it, creating the fixed started destination.
                fragmentManager.beginTransaction()
                    .attach(selectedFragment)
                    .setPrimaryNavigationFragment(selectedFragment)
                    .apply {
                        // Detach all other Fragments
                        graphIdToTagMap.forEach { _, fragmentTagIter ->
                            if (fragmentTagIter != newlySelectedItemTag) {
                                detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
                            }
                        }
                    }
                    .addToBackStack(firstFragmentTag)
                    .setCustomAnimations(
                        R.anim.nav_default_enter_anim,
                        R.anim.nav_default_exit_anim,
                        R.anim.nav_default_pop_enter_anim,
                        R.anim.nav_default_pop_exit_anim)
                    .setReorderingAllowed(true)
                    .commit()
            }
            selectedItemTag = newlySelectedItemTag
            isOnFirstFragment = selectedItemTag == firstFragmentTag
            selectedNavController.value = selectedFragment.navController
            true
        } else {
            false
        }
    }
}

// Optional: on item reselected, pop back stack to the destination of the graph
setupItemReselected(graphIdToTagMap, fragmentManager)

// Handle deep link
setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)

// Finally, ensure that we update our BottomNavigationView when the back stack changes
fragmentManager.addOnBackStackChangedListener {
    if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
        this.selectedItemId = firstFragmentGraphId
    }

    // Reset the graph if the currentDestination is not valid (happens when the back
    // stack is popped after using the back button).
    selectedNavController.value?.let { controller ->
        if (controller.currentDestination == null) {
            controller.navigate(controller.graph.id)
        }
    }
}
return selectedNavController

}

此示例代码,您可以在此处找到完整的代码

https://github.com/android/architecture-components-samples/tree/master/NavigationAdvancedSample