片段弹出调用 OnViewCreated 在 PopBackStack 之后

时间:2021-04-04 16:55:57

标签: android android-fragments android-lifecycle fragmenttransaction

我有 1 个 Activity 和 3 个 Fragment。 (A、B 和 C)。所以,

Activity -> FragmentContainerView 带片段 A

    <androidx.fragment.app.FragmentContainerView
    android:id="@+id/host_fragment"
    android:name="cl.gersard.shoppingtracking.ui.product.list.ListProductsFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="ListProductsFragment" />

片段 A 有一个按钮可以转到片段 B

片段 A -> 片段 B(使用 addToBackStack)

然后,我从片段 B 到片段 C

片段 B -> 片段 C(没有 addToBackStack)

当我在 Fragment C 中保存一个项目时,我需要返回到 Fragment A,所以我不使用 addToBackStack。

问题是我在 Fragment C 中使用时

requireActivity().supportFragmentManager.popBackStack()

requireActivity().onBackPressed()

片段 A 出现,但调用了片段 C 中的 OnViewCreated 方法,因此执行我在片段 C 中的验证。

我需要从 Fragment C 返回到 Fragment A 而不调用 Fragment C 的 OnViewCreated

感兴趣的代码

主活动

fun changeFragment(fragment: Fragment, addToBackStack: Boolean) {
    val transaction = supportFragmentManager.beginTransaction()
        .replace(R.id.host_fragment, fragment,fragment::class.java.simpleName)
    if (addToBackStack) transaction.addToBackStack(null)
    transaction.commit()
}

片段 A (ListProductsFragment)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    setupRecyclerView()
    observeLoading()
    observeProducts()
    viewModel.fetchProducts()
    viewBinding.btnEmptyProducts.setOnClickListener { viewModel.fetchProducts() }
    viewBinding.fabAddPurchase.setOnClickListener { addPurchase() }
}

    private fun addPurchase() {
    (requireActivity() as MainActivity).changeFragment(ScanFragment.newInstance(),true) 
}

片段 B(扫描片段)

    override fun barcodeDetected(barcode: String) {
    if (processingBarcode.compareAndSet(false, true)) {
        (requireActivity() as MainActivity).changeFragment(PurchaseFragment.newInstance(barcode), false)
    }
}

片段 C(购买片段)

    private fun observePurchaseState() {
    viewModel.purchasesSaveState.observe(viewLifecycleOwner, { purchaseState ->
        when (purchaseState) {
            is PurchaseSaveState.Error -> TODO()
            is PurchaseSaveState.Loading -> manageProgress(purchaseState.isLoading)
            PurchaseSaveState.Success -> {
                Toast.makeText(requireActivity(), getString(R.string.purchase_saved_successfully), Toast.LENGTH_SHORT).show()
                requireActivity().supportFragmentManager.popBackStack()
            }
        }
    })
}

完整代码在这里https://github.com/gersard/PurchaseTracking

1 个答案:

答案 0 :(得分:1)

好的,我想我明白了你的问题。您有条件地向 backstack 添加东西,这使片段管理器处于一种奇怪的状态。

问题

您从 Main 开始,将 Scanner 添加到 back stack,而不是 Product。因此,当您按下返回键时,您将 Scanner 从堆栈中弹出,但 Product 保留在 FragmentManager 中。这就是为什么每次扫描并返回时都会获得一个新实例。 为什么我不清楚会发生这种情况 - 似乎可能是 Android 错误?您正在替换片段,所以奇怪的是额外的实例正在构建。

一个解决方案

将您的 changeFragment 实现更改为有条件地弹出堆栈,而不是有条件地向其中添加内容。

fun changeFragment(fragment: Fragment, popStack: Boolean) {
    if (keepStack) supportFragmentManager.popBackStack()

    val transaction = supportFragmentManager.beginTransaction()
        .replace(R.id.host_fragment, fragment,fragment::class.java.simpleName)
    transaction.addToBackStack(null) // Always add the new fragment so "back" works
    transaction.commit()
}

然后反转调用 changeFragment 的当前逻辑:

private fun addPurchase() {
    // Pass false to not pop the main activity
    (requireActivity() as MainActivity)
        .changeFragment(ScanFragment.newInstance(), false)
}

还有……

override fun barcodeDetected(barcode: String) {
    if (processingBarcode.compareAndSet(false, true)) {
        // Pass true to pop the barcode that's currently there
        (requireActivity() as MainActivity)
        .changeFragment(PurchaseFragment.newInstance(barcode), true)
    }
}
相关问题