I have the following Activity:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
with the following layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/navHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
I also have two fragments: Fragment1 and Fragment2. Fragment1 is:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
class Fragment1 : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_1, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findNavController().navigate(R.id.action_fragment1_to_fragment2)
}
}
and its layout is:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment1">
<TextView
android:id="@+id/toFragment2Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Fragment 1" />
</FrameLayout>
Fragment2 is:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class Fragment2 : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_2, container, false)
}
}
with the following layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment2">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 2" />
</FrameLayout>
and last but not least is the contents of navigation_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/fragment1">
<fragment
android:id="@+id/fragment1"
android:name="ir.fallahpoor.navigation.Fragment1"
android:label="fragment_1"
tools:layout="@layout/fragment_1">
<action
android:id="@+id/action_fragment1_to_fragment2"
app:destination="@id/fragment2" />
</fragment>
<fragment
android:id="@+id/fragment2"
android:name="ir.fallahpoor.navigation.Fragment2"
android:label="fragment_2"
tools:layout="@layout/fragment_2" />
</navigation>
As you can see there is nothing fancy here. The only thing that I'm doing is navigating to Fragment2 in onViewCreated
of Fragment1.
When I run the app Fragment2 is displayed as expected. When I press the back button I expect to return to Fragment1, but that doesn't happen. It is as if back button is disabled and pressing it doesn't do anything. I have to press the home button to exit the app.
The Reason for the reported behavior is your code simulated an infinite loop. You should not call
findNavController().navigate(R.id.action_fragment1_to_fragment2)
from onViewCreated() instead use a button or any form of trigger to perform the navigation.
Your Flow:
STEP 1: onViewCreated() of fragment1 is called when the app launched and the app is navigated to fragment2.
STEP 2: As soon as the application navigates to fragment2, the fragment1 view is destroyed. i.e. onDistroyView() is called on fragment1.
STEP 3: The moment you hit the back button from fragment2, fragment1 is pulled from the back stack, since its view is destroyed, it goes through the view creation cycle again. i.e. onViewCreated() is called again. as a result, your app is stuck with infinite loop.