Adding fragment manually into the backstack in Navigation Architecture Component - android

I am having 4 fragments in Navigation Graph, Named A, B, C, D, On which i am getting some data from the user.
When i an in a normal flow (A->B->C->D) and press back button everything(back-stack) working fine.
But i have a case in which i have and edit information flow, Suppose user left the form on Fragment D so when user come again on the screen, i have to navigate the user on the same screen i.e. Fragment D.
I achieved it via Deep-link.
Now the problem is in the above case there will be no fragment in the Stack other than fragment D. But i need when user press back button it should navigate to Fragment C to Fragment B to Fragment A .
Means i want other Fragments(A,B,C) to add in the back-stack. Can we do the same, if yes, how?
===Here is the code===
my_navigation_graph.xml.
<fragment
android:id="#+id/aFragment"
android:name="in.demo.project.AFragment"
android:label="AFragment"
tools:layout="#layout/fragment_a_layout">
<deepLink
android:id="#+id/deepLink"
android:autoVerify="true"
app:uri="demo://editflow?is_for_edit={is_for_edit}&step={step}" />
<argument
android:name="is_for_edit"
android:defaultValue="false"
app:argType="boolean" />
<argument
android:name="step"
android:defaultValue="2"
app:argType="string" />
<action
android:id="#+id/action_aFragment_to_bFragment"
app:destination="#id/bFragment"/>
<action
android:id="#+id/action_aFragment_to_cFragment"
app:destination="#id/cFragment"/>
<action
android:id="#+id/action_aFragment_to_dFragment"
app:destination="#id/dFragment"/>
<fragment
android:id="#+id/bFragment"
android:name="in.demo.project.BFragment"
android:label="BFragment"
tools:layout="#layout/fragment_b_layout">
<action
android:id="#+id/action_bFragment_to_cFragment"
app:destination="#id/cFragment" />
</fragment>
<fragment
android:id="#+id/cFragment"
android:name="in.demo.project.CFragment"
android:label="CFragment"
tools:layout="#layout/fragment_c_layout">
<action
android:id="#+id/action_cFragment_to_dFragment"
app:destination="#id/dFragment" />
</fragment>
<fragment
android:id="#+id/dFragment"
android:name="in.demo.project.DFragment"
android:label="DFragment"
tools:layout="#layout/fragment_d_layout">
</fragment>
Navigating through.
findNavController().navigate(AFragmentDirections.actionAFragmentToBFragment())
Inside AFragment i am redirecting to other fragment, assuming that
creating deep-link to every fragment is not good practice.
This code is in onCreate() Method of AFragment
arguments?.let {
if (AFragmentArgs.fromBundle(it).isForEdit) {
redirectionForEdit(AFragmentArgs.fromBundle(it).step)
}
}
and a function for redirection
private fun redirectionForEdit(step: String) {
when (step) {
"2" ->
findNavController().navigate(AFragmentDirections.actionAFragmentToBFragment())
"3" ->
findNavController().navigate(AFragmentDirections.actionAFragmentToCFragment())
"4" ->
findNavController().navigate(AFragmentDirections.actionAFragmentToDFragment())
}
}
Now if i get 4 in the step it'll redirect to DFragment, so the stack would be A->D, but i want B & D into the stack too (A->B->C->D).

For this please refer handling custom back navigation under navigation components
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
#Override
public void handleOnBackPressed() {
// Handle the back button event
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);

Related

How can I back from the second fragment to the first fragment using Navigation Component?

How can I back from the second fragment to the first fragment using Navigation Component?
navigation_main.xml
<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/main_navigation"
app:startDestination="#id/firstFragment">
<fragment
android:id="#+id/firstFragment"
android:name="com.test.ttt.FirstFragment"
tools:layout="#layout/fragment_first">
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"
app:popUpTo="#id/firstFragment"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.test.ttt.SecondFragment"
tools:layout="#layout/fragment_second" />
</navigation>
FirstFragment.java
public class FirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Navigation.findNavController(container).navigate(FirstFragmentDirections.actionFirstFragmentToSecondFragment());
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
I want when I press the back button in the second fragment, It must back to the first fragment but currently, When I press the back button in the second fragment it is leaving the app.
How can I solve this problem?
The reason you are being exited from the app is because while navigating to the second fragment, you are removing the first fragment from your stack. The properties app:popUpTo and app:popUpToInclusive are typically used when you want to remove some fragments from your backstack while navigating. A simple use case for this would be when navigating from Login/SignUp Fragment to Home/Main Fragment. In this case you would not want the user to be able to press back and go back to login/signup screens. Here is where the two properties would help.
TL;DR - Remove the app:popUpTo and app:popUpToInclusive properties from your action
Change
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"
app:popUpTo="#id/firstFragment"
app:popUpToInclusive="true"/>
to
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment"/>

Navigation graph with viewpager2 android

My viewpager consists of 2 fragments which are displayed correctly and working fine.
From viewpager's fragment I want to move to another fragment via navigation graph
This is my graph
<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/offer_nav_graph"
app:startDestination="#id/offersFragment">
<fragment
android:id="#+id/offersFragment"
android:name="com.octave.offers.OffersFragment"
android:label="offers_fragment"
tools:layout="#layout/offers_fragment" />
<fragment
android:id="#+id/availableOfferDetailFragment"
android:name="com.octave.offers.available.AvailableOfferDetailFragment"
android:label="fragment_available_offer_detail"
tools:layout="#layout/fragment_available_offer_detail" />
<fragment
android:id="#+id/availableOffersFragment"
android:name="com.octave.offers.available.AvailableOffersFragment"
android:label="fragment_available_offers"
tools:layout="#layout/fragment_available_offers" >
<action
android:id="#+id/action_availableOffersFragment_to_availableOfferDetailFragment"
app:destination="#id/availableOfferDetailFragment" >
<argument
android:name="offerId"
app:argType="integer"
android:defaultValue="-1" />
</action>
</fragment>
</navigation>
Offers fragment - has view pager
Available offer fragment - one of the fragment on view pager
Available offer detail fragment - i want to navigate
On button click I am calling this
AvailableOffersFragmentDirections.actionAvailableOffersFragmentToAvailableOfferDetailFragment(offerId)
The exception
Navigation action/destination com.octave.staging:id/action_availableOffersFragment_to_availableOfferDetailFragment cannot be found from the current destination Destination(com.octave.staging:id/homeFragment) label=HomeFragment class=com.octave.home.HomeFragment
What is wrong over here?
button exists on availableOffersFragment. I want to navigate from
availableOffersFragment to availableOfferDetailFragment.
offersFragment has the viewpager with 2 tabs having their own fragment
availableOffersFragment and secondFragemnt
So, now you need to navigate from availableOffersFragment which is a tab (page fragment) in the ViewPager; but this is not possible because those tabs don't affect the back stack. You can check out the questions discussed in here and also this one.
But what you can do instead is to add an action from offersFragment (which holds the ViewPager) to availableOfferDetailFragment as following:
Remove the tab fragments from the navGraph (availableOffersFragment and secondFragemnt).
Create an action in the navGraph from offersFragment to availableOfferDetailFragment
<fragment
android:id="#+id/offersFragment"
android:name="com.octave.offers.OffersFragment"
android:label="offers_fragment"
tools:layout="#layout/offers_fragment">
<action
android:id="#+id/action_offersFragment_to_availableOfferDetailFragment"
app:destination="#id/availableOfferDetailFragment" >
<argument
android:name="offerId"
app:argType="integer"
android:defaultValue="-1" />
</action>
</fragment>
When the button is clicked use parentFragment to access the offersFragment from the availableOffersFragment tab when the button is clicked. For instance:
Create a method in offersFragment:
goToDetailsFragment(offerId: Int) {
// perfrom the navaigation
OffersFragmentDirections.actionOffersFragmentToAvailableOfferDetailFragment(offerId)
}
And in availableOffersFragment
btn.setOnClickListener {
(parentFragment as offersFragment).goToDetailsFragment(offerId)
}
Check using:
btn.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.availableOfferDetailFragment)
}

How can I go back directly to Fragment A since Fragment D without going back to Fragment C?

I use Android Navigation Architecture Component.
I have three Fragment A, B and C
Fragment A -> Fragment B -> Fragment D
Fragment A -> Fragment C -> Fragment D
On fragment D I have a button used to validate modifications and finish.
From this Frgament D I would like to:
return to Fragment B when I come from Fragment B (I use findNavController().navigateUp())
come back to Fragment A when I come from Fragment C (I don't know how to do it)
How can I go back directly to Fragment A when I come from Fragment D without going back to Fragment C?
Should I wait for the return on Fragment C and reprocess for the execution of findNavController().NavigateUp().
I use setPopUpTo on NavOptions, or you can use it inside the xml as well
documentation => https://developer.android.com/reference/androidx/navigation/NavOptions.Builder#setPopUpTo(int,%20boolean)
You can achieve both of these action with findNavController().NavigateUp()
Given the following graph for example:
<?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/test_nav_graph"
app:startDestination="#id/a">
<fragment
android:id="#+id/a"
android:name="fragment.A"
tools:layout="#layout/a_fragment"
android:label="A" >
<action
android:id="#+id/action_a_to_b"
app:destination="#id/b" />
<action
android:id="#+id/action_a_to_c"
app:destination="#id/c" />
</fragment>
<fragment
android:id="#+id/b"
android:name="fragment.B"
tools:layout="#layout/b_fragment"
android:label="B" >
<action
android:id="#+id/action_b_to_d"
app:destination="#id/d" />
</fragment>
<fragment
android:id="#+id/c"
tools:layout="#layout/c_fragment"
android:name="fragment.C"
android:label="C" >
<action
android:id="#+id/action_c_to_d"
app:destination="#id/d"
app:popUpTo="#id/a"/>
</fragment>
<fragment
android:id="#+id/d"
tools:layout="#layout/d_fragment"
android:name="fragment.D"
android:label="D" />
</navigation>
When you take the path: A->B->D your back stack is A,B,D and when you call NavigateUp() you go back to B.
Now the path A->C->D has a minor addition in the action tag as you can see
<action
android:id="#+id/action_c_to_d"
app:destination="#id/d"
app:popUpTo="#id/a"/>
it has popUpTo, so when you navigate from C to D app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(), so after navigating to D your back stack is A,D and NavigateUp() takes you back to A
So when you are in Fragment D and pressing back button . You can check the fragment stack and check for example
onBackPress(){
childFragmentManager.popbackstack()
val currentFragment = findFragmentByTag("FRAGMENT_B")
if(currentFragment == childFragmentManager.primaryNavigation()){
childFragmentManager.popbackstack()
}
NOTE
Above snippet is written without editor. You can use this logic.

Is it possible to start with a "non-start" fragment using Android Navigation Architecture Component(Android Jetpack)?

so I have the following navigation graph:
Fragment A (start) --> Fragment B
So for some situations (firebase notifications), I need to start Fragment B directly, passing data from the notifications. Now, this works. However, when I press the back button, it results in a crash. Is it because the leading fragment (Fragment A) is not in the stack? If so, is there a way to properly handle this.
Basically, I need the backPressed action to launch the start Fragment (Fragment A) in a situation where Fragment B is launched directly without passing through Fragment A.
Below is a snippet of my graph:
<fragment
android:id="#+id/homeFragment"
android:name="dita.dev.myportal.ui.home.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_homeFragment_to_messageDetailFragment"
app:destination="#id/messageDetailFragment"
app:exitAnim="#anim/fade_out_animation" />
</fragment>
<fragment
android:id="#+id/messageDetailFragment"
android:name="dita.dev.myportal.ui.messages.details.MessageDetailFragment"
android:label="Message"
tools:layout="#layout/fragment_message_detail">
<argument
android:name="title"
app:argType="string" />
<argument
android:name="message"
app:argType="string" />
</fragment>
I hope the link helps.
https://developer.android.com/guide/navigation/navigation-deep-link
Deep links allow for synthetic back-stacks.
Quoted from the website, "This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point."
Maybe trying to create a deep link for Fragment B will work.

Android NavigationUI - Handle backpress when starting fragment is poped out

I am using NavigationUI of android architecture components with bottom navigation in my android app. I have the following situation
The app starts at Fragment A
Initial calculation is done and now I pop out Fragment A by navController.popBackStack()
The app goes to Fragment B (This serves as a 'Home' for the app)
Now there are more fragments say C and D
The user can navigate between B, C and D
Now the problem is in my navigation graph, my starting fragment was A (by defining app:startDestination="#id/fragmentA") but that is now pop out of the activity. Due to this, anytime if I backpress, the app just closes instead going back to the previous fragment. For example, let's say I navigate to Fragment C or D from fragment B and if I press back button, my app will close instead of going to fragment B. If the there way to 'reassign' the startDestination?
I checked the answer to this question which has a similar situation as above but using NavOptions is somehow not working. Is there any other way? Following is the code I used to pop fragment and add nav options
navController.popBackStack()
val navOptions: NavOptions = NavOptions.Builder()
.setPopUpTo(R.id.homeFragment, true)
.build()
navController.navigate(R.id.action_fragmentA_to_fragmentB, null, navOptions)
Use this navigation graph. Hope it will solve your problem.
<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/nav_graph"
app:startDestination="#id/fragment_a">
<fragment
android:id="#+id/fragment_a"
tools:layout="#layout/fragment_a">
<action
android:id="#+id/action_a_to_b"
app:destination="#id/fragment_b"
app:popUpTo="#id/fragment_a"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/fragment_b"
tools:layout="#layout/fragment_b">
<action
android:id="#+id/action_b_to_c"
app:destination="#id/fragment_c"/>
</fragment>
<fragment
android:id="#+id/fragment_c"
tools:layout="#layout/fragment_c">
</fragment>
</navigation>
Use the following line for navigation:
navController.navigate(R.id.action_a_to_b)
navController.navigate(R.id.action_b_to_c)

Categories

Resources