我有 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()
}
}
})
}
答案 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)
}
}