Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Navigation Component back button not working

Tags:

I'm using the Navigation Component in android where I have set 6 fragments initially. The problem is when I added a new fragment (ProfileFragment).

When I navigate to this new fragment from the start destination, pressing the native back button does not pop the current fragment off. Instead, it just stays to the fragment I'm in - the back button does nothing.

Here's my navigation.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"     android:id="@+id/dashboard_navigation"     app:startDestination="@id/dashboardFragment"     >                  <fragment                     android:id="@+id/dashboardFragment"                     android:name="com.devssocial.localodge.ui.dashboard.ui.DashboardFragment"                     android:label="DashboardFragment"                     >                                 <action                                     android:id="@+id/action_dashboardFragment_to_newPostFragment"                                     app:destination="@id/newPostFragment"                                     app:enterAnim="@anim/slide_in_up"                                     app:exitAnim="@anim/slide_out_down"                                     app:popEnterAnim="@anim/slide_in_up"                                     app:popExitAnim="@anim/slide_out_down"                                     />                                 <action                                     android:id="@+id/action_dashboardFragment_to_notificationsFragment"                                     app:destination="@id/notificationsFragment"                                     app:enterAnim="@anim/slide_in_up"                                     app:exitAnim="@anim/slide_out_down"                                     app:popEnterAnim="@anim/slide_in_up"                                     app:popExitAnim="@anim/slide_out_down"                                     />                                 <action                                     android:id="@+id/action_dashboardFragment_to_mediaViewer"                                     app:destination="@id/mediaViewer"                                     app:enterAnim="@anim/slide_in_up"                                     app:exitAnim="@anim/slide_out_down"                                     app:popEnterAnim="@anim/slide_in_up"                                     app:popExitAnim="@anim/slide_out_down"                                     />                                 <action                                     android:id="@+id/action_dashboardFragment_to_postDetailFragment"                                     app:destination="@id/postDetailFragment"                                     app:enterAnim="@anim/slide_in_up"                                     app:exitAnim="@anim/slide_out_down"                                     app:popEnterAnim="@anim/slide_in_up"                                     app:popExitAnim="@anim/slide_out_down"                                     />                              ====================== HERE'S THE PROFILE ACTION ====================                                                                 <action                                     android:id="@+id/action_dashboardFragment_to_profileFragment"                                     app:destination="@id/profileFragment"                                     app:enterAnim="@anim/slide_in_up"                                     app:exitAnim="@anim/slide_out_down"                                     app:popEnterAnim="@anim/slide_in_up"                                     app:popExitAnim="@anim/slide_out_down"                                     />                             =====================================================================                                                  </fragment>                    <fragment                     android:id="@+id/profileFragment"                     android:name="com.devssocial.localodge.ui.profile.ui.ProfileFragment"                     android:label="fragment_profile"                     tools:layout="@layout/fragment_profile"                     /> </navigation> 

enter image description here

In the image above, the highlighted arrow (in the left) is the navigation action I'm having troubles with.

In my Fragment code, I'm navigating as follows:

findNavController().navigate(R.id.action_dashboardFragment_to_profileFragment) 

The other navigation actions are working as intended. But for some reason, this newly added fragment does not behave as intended.

There are no logs showing when I navigate to ProfileFragment and when I press the back button.

Am I missing something? or is there anything wrong with my action/fragment configurations?

EDIT: I do not do anything in ProfileFragment. Here's the code for it:

class ProfileFragment : Fragment() {      override fun onCreateView(         inflater: LayoutInflater, container: ViewGroup?,         savedInstanceState: Bundle?     ): View? {         // Inflate the layout for this fragment         return inflater.inflate(R.layout.fragment_profile, container, false)     }   } 

And my activity xml containing the nav host:

<?xml version="1.0" encoding="utf-8"?> <FrameLayout         xmlns:android="http://schemas.android.com/apk/res/android"         xmlns:app="http://schemas.android.com/apk/res-auto"         android:layout_width="match_parent"         android:layout_height="match_parent">      <fragment             android:id="@+id/dashboard_navigation"             app:layout_behavior="@string/appbar_scrolling_view_behavior"             android:name="androidx.navigation.fragment.NavHostFragment"             android:layout_width="match_parent"             android:layout_height="match_parent"             app:navGraph="@navigation/dashboard_navigation"             app:defaultNavHost="true"/>  </FrameLayout> 
like image 430
Christilyn Arjona Avatar asked Jan 21 '20 04:01

Christilyn Arjona


People also ask

How do I navigate back on android?

You can go back more than once. But when you reach the Home screen, you can't go back any further. Gesture navigation: Swipe from the left or right edge of the screen. 2-button navigation: Tap Back .

How do I get the back button on my Android toolbar?

Toolbar toolbar = findViewById(R. id. toolbar); setSupportActionBar(toolbar); getSupportActionBar(). setDisplayHomeAsUpEnabled(true);


2 Answers

if you are using setupActionBarWithNavController in Navigation Component such as:

 setupActionBarWithNavController(findNavController(R.id.fragment)) 

then also override and config this methods in your main activity:

 override fun onSupportNavigateUp(): Boolean {     val navController = findNavController(R.id.fragment)     return navController.navigateUp() || super.onSupportNavigateUp() } 

My MainActivity.kt

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     setContentView(R.layout.activity_main)      setupActionBarWithNavController(findNavController(R.id.fragment)) }  override fun onSupportNavigateUp(): Boolean {     val navController = findNavController(R.id.fragment)     return navController.navigateUp() || super.onSupportNavigateUp() } } 
like image 69
nirazverma Avatar answered Oct 01 '22 15:10

nirazverma


For anyone using LiveData in a previous Fragment which is a Home Fragment, whenever you go back to the previous Fragment by pressing back button the Fragment is starting to observe the data and because ViewModel survives this operation it immediately emits the last emitted value which in my case opens the Fragment from which I pressed the back button, that way it looks like the back button is not working the solution for this is using something that emits data only once. I used this :

class SingleLiveData<T> : MutableLiveData<T>() {  private val pending = AtomicBoolean()  /**  * Adds the given observer to the observers list within the lifespan of the given  * owner. The events are dispatched on the main thread. If LiveData already has data  * set, it will be delivered to the observer.  *  * @param owner The LifecycleOwner which controls the observer  * @param observer The observer that will receive the events  * @see MutableLiveData.observe  */ @MainThread override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {     super.observe(owner, Observer { t ->         if (pending.compareAndSet(true, false)) {             observer.onChanged(t)         }     }) }  /**  * Sets the value. If there are active observers, the value will be dispatched to them.  *  * @param value The new value  * @see MutableLiveData.setValue  */ @MainThread override fun setValue(value: T?) {     pending.set(true)     super.setValue(value) } 
like image 38
trOnk12 Avatar answered Oct 01 '22 16:10

trOnk12