For example I have one activity and three fragments (1, 2, 3).
I show first fragment, then second fragment (adding it to back stack) and third fragment (no adding it to back stack because when pressing the back button I want to go to the first fragment from the current third one instead of going to the second fragment)
This logic works but when it go back to first fragment, third fragment is still visible (two fragments are displayed at the same time)
Here's the full flow example and the full code when Fragment 1 and Fragment 3 are displayed at the same time
Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showFragment(
addToBackStack = false,
backStackName = null,
fragmentNumber = 1,
tag = "FRAGMENT_FIRST"
)
// simulate going to other fragments sequentially
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.postDelayed(
{
showFragment(
addToBackStack = true,
backStackName = null,
fragmentNumber = 2,
tag = "FRAGMENT_SECOND"
)
},
1000L
)
mainHandler.postDelayed(
{
showFragment(
addToBackStack = false, // when back pressing from third fragment I want it to get back to first fragment, not second
backStackName = null,
fragmentNumber = 3,
tag = "FRAGMENT_THIRD"
)
},
2000L
)
}
private fun showFragment(
addToBackStack: Boolean,
backStackName: String?,
fragmentNumber: Int,
tag: String
) {
val transaction = supportFragmentManager.beginTransaction()
var fragment =
supportFragmentManager.findFragmentByTag(tag) as FragmentGeneral?
if (fragment == null) {
fragment = FragmentGeneral.newInstance(number = fragmentNumber)
transaction.replace(R.id.fragment_container, fragment, tag)
if (addToBackStack) {
transaction.addToBackStack(backStackName)
}
} else {
transaction.show(fragment)
}
transaction.commit()
}
}
class FragmentGeneral : Fragment() {
private lateinit var binding: FragmentGeneralBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
) = FragmentGeneralBinding.inflate(layoutInflater, container, false).apply {
binding = this
}.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
arguments?.getInt(ARG_FRAGMENT_NUMBER)?.let { number ->
binding.fragmentNumber = number
// set different position of the text so we could clearly see overlapping of two fragments
binding.textView.gravity = when (number) {
1 -> Gravity.TOP
2 -> Gravity.CENTER_VERTICAL
3 -> Gravity.BOTTOM
else -> return
}
// simulate pressing back button pressing
if (number == 3) {
// should go to first fragment because it wasn't added to backstack
Handler(Looper.getMainLooper()).postDelayed(
{ activity?.onBackPressed() },
1000L
)
}
}
}
companion object {
private const val ARG_FRAGMENT_NUMBER = "ARG_FRAGMENT_NUMBER"
fun newInstance(number: Int) =
FragmentGeneral().apply {
arguments = bundleOf(ARG_FRAGMENT_NUMBER to number)
}
}
}
activity_main.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</layout>
fragment_general.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".FragmentGeneral">
<data>
<variable
name="fragmentNumber"
type="int" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:text='@{"Fragment #" + fragmentNumber}'
android:textColor="@android:color/black"
android:textSize="64sp"
tools:text="Fragment #?" />
</FrameLayout>
</layout>
So why third fragment is still visible? How to fix this issue and what is correct way to handle such transactions?
Developers usually would not notice such issues if their fragments are not transparent, but in my example it's transparent, so the white background - it's activity background