Remove multiple fragment transactions in Android - IllegalStateException - android

I reveive an error when trying to pop the backstack after adding several fragments.
In my app I have one main activity, and multiple fragments.
The error occurs in the following way: First the user is in frag 1. He navigates to frag 2, and then to frag 3. This navigation is done by using fragmentTransaction.addToBackStack(null)
After going from frag 1 -> frag 2 -> frag 3, I navigate to frag 4 the same way. However, when I am finished in frag 4, I replace fragment 4 with fragment 3 without adding to the backstack. This way I can include a bundle in the fragment's arguments (instead of just popping the backstack). When I am back in frag 3, and if I hit the back button, the back stack will be popped, but I receive this error:
java.lang.IllegalStateException: Fragment already added: EditFragment...
Note: I do not want to the pop the backstack when going from fragment 4 to fragment 3 because sometimes I end up having a more complicated navigation than the one explained here.

Related

Navigation Component: Navigate from Fragment in Viewpager to another Fragment

I have a Fragment A which navigates to Fragment B
Fragment B hosts a ViewPager2.
ViewPager2 has two fragments inflated in it - Fragment C and Fragment D.
On clicking an item in Fragment C I want to navigate to a new instance of Fragment D on top of Fragment B.
Currently, my code is something like this -
findNavController().navigate(
R.id.action_FragmentC_to_FragmentD,
bundleOf("id" to id, "type" to "list")
)
However, when I try to navigate I get the following exception -
java.lang.IllegalArgumentException: Navigation action/destination com.test.at:id/action_FragmentC_to_FragmentD cannot be found from the current destination Destination(com.krtkush.audiotime:id/FragmentB) label=FragmentB
From what I can understand is that the navigation component is still on Fragment B but I'm trying to navigate to Fragment D from Fragment C and hence it is throwing an exception.
I (think) can fix this by adding a listener which informs Fragment B when the item is tapped in Fragment C and then navigate to Fragment D from Fragment B. However, this will make my Fragment C tightly coupled to Fragment B which I don't want to. Anyway to fix this is another way?
If you do not navigate() to Fragment C and Fragment D, you will remain on the last destination you navigated to: Fragment B, that is the expected behavior. The NavController knows nothing about child fragments such as fragments within a ViewPager of Fragment B and therefore you were never on Fragment C as a destination.
If you never navigate() to Fragment C and it is only viewable as part of your ViewPager, then Fragment C should not be in your graph. Any actions from fragments within Fragment B's ViewPager should be actions on Fragment B directly (the destination you're actually on).
Note that you can reuse the same actions names on fragments such as Fragment D if you are also using them as standalone destinations in your graph (thus ensuring that the action is available in both cases).

Recreating backstack with Android Navigation Architecture Component

I am trying to implement navigation to specific Detail pages of my app using PendingIntent from a notification, however I am having problems recreating the backstack from the Detail page all the way back to the start destination.
I made a sample app here with a single activity and three fragments to demo this:
Fragment 1 -> Fragment 2 -> Fragment 3
(start dest) <- <-
From Fragment 1 (the start destination), I navigate directly to Fragment 3 using
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.fragment2,
null,
NavOptions.Builder()
.build())
From Fragment 3, when I call Navigation.findNavController(this,R.id.nav_host_fragment).navigateUp() I am navigated back to Fragment 1. Is there a way to get this to navigate to a newly created Fragment 2 instead?
Thanks to M.G for pointing to the right direction, I have managed to solve this by manually creating the backstack using the navigation library. This means sequentially calling findNavController(...).navigate(...) multiple times to create a backstack.
For example when I deep link to fragment 3 but want an up navigation back to fragments 1 and 2, I call:
findNavController.navigate(R.id.fragment1, ...)
findNavController.navigate(R.id.fragment2, ...)
findNavController.navigate(R.id.fragment3, ...)

Android: Not getting how popBackStackImmediate () behaves

I have 3 Fragments and the flow is like
Fragment 1 --> Fragment 2 (adding it to back stack)--> Fragment 3 --> Fragment 1
As I want to go to Fragment 1 from Fragment 3 again, I want the back stack to be clean so that when user press back nothing happens.
Intially I have cleared popback stack at Fragment 3
Boolean isPoped = fManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
And then created a new Instance of my fragment 1
HomeFragment homeFragment = HomeFragment.newInstance(mobileNumber, "");
FragmentTransaction transaction =fManager.beginTransaction();
transaction.replace(R.id.fragment_container, homeFragment);
transaction.commit();
which caused
android: ViewPager throwing null pointer
then I commented the above code and only used
Boolean isPoped = fManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
which works fine as it removed the transactions(that I belive) and took me to homeFragment but that caused View pager not instantiating post fragment popBackStackImmediate
Here I am not getting how popBackStack works? All I want is to take user from Fragment 3 to Fragment 1 and clear the backstack.
I looked at your code in the other question and I think I understand what the problem is.
So your first action is that you create Fragment 1 and put it in a container. I don't see code for that but no matter; if the container is empty then add and replace act the same way. So now your Fragment 1 is in the container.
You haven't called addToBackStack here so the FragmentManager doesn't know how to undo this operation. That's fine, it's the first operation and doesn't need to be undone.
Next you create Fragment 2 and do a replace transaction. Fragment 1 is replaced with Fragment 2. This is pushed to the back stack so the FragmentManager does know how to undo this transaction.
Next you create Fragment 3 and do a replace transaction. Fragment 2 is replaced with Fragment 3. You don't push this operation to the back stack. Uh oh.
Now when you say popBackStack (deferred or immediate) the FragmentManager goes to undo the operation to replace Fragment 2 with Fragment 1 but Fragment 2 isn't in the container anymore. So (from what I understand) the FragmentManager will put Fragment 1 back in the container but leave Fragment 3 there. It doesn't know what to do with Fragment 3.
Here is how I handle those kinds of scenarios: Say I have Fragment 1, then navigate to Fragment 2. To navigate to Fragment 3 when I intend the back button to go to Fragment 1, I do this:
Pop the back stack (immediate, now Fragment 1 is back in the container) then
Replace Fragment 1 with Fragment 3 and push that operation to the back stack.
Now when I press the back button, the FragmentManager knows how to undo my operation and puts Fragment 1 back where Fragment 3 was. This means that I don't have to perform any fragment transactions to handle this back navigation, the FragmentManager handles it all for me.

No view found for id when popping backstack without adding to backstack

I am working on an Android app and have encountered an error involving Fragments and FragmentTransactions. I have created an example app to demonstrate the problem. Here is what I am doing:
add Fragment1 to fragmentSpace, without adding to backstack.
replace fragmentSpace with Fragment2, adding to backstack as "beginning".
add Fragment3 to fragmentSpace2 (which is inside of Fragment2), without adding to backstack.
replace fragmentSpace2 with Fragment4, adding to backstack as null.
Call getFragmentManager().popBackStack("beginning", FragmentManager.POP_BACK_STACK_INCLUSIVE); in an attempt to undo all the Transactions, which should bring the user back to seeing only Fragment1.
However, the app crashes on step 5 with this error:
java.lang.IllegalArgumentException: No view found for id 0x7f090004 (me.MitchT.testfragmenttransactions:id/fragmentSpace2) for fragment Fragment3{7f35cb6 #2 id=0x7f090004}
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:886)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:1645)
...
I have found that if I add step 3 to the backstack, step 5 no longer crashes the app and there is no more error. Why?
The problem I have with adding step 3 to the backstack is that I want the user to be able to press the back button after Fragment3 is added and go back to Fragment1. If I add it to the backstack, then when the user presses the back button it removes Fragment3, but Fragment2 is still visible, so they must press the back button again. I am trying to avoid that double-back-button behavior.
I did not feel it was necessary to post the code for every single file in the example app on this question, so instead I created a gist.
So I guess my questions are:
Why do I get this error?
Why don't I get the error after adding step 3 to the backstack?
Is there a better way of "going back to the beginning" or going back two fragments at a time?
Thanks!
From what i understand. You have a fragment layout which is the container in activity
Activity hosts Fragment1. Then you replace Fragment 1 by Fragment 2 ( added to back stack.
At this stage clicking back button you will have fragment2 popped and you see the activity which hosts fragment1.
Fragment2 has a framelayout which holds fragment3. Then you have Fragment4 replacing fragment3 which is added to back stack.
Now clicking the button you have getFragmentManager().popBackStack("beginning", FragmentManager.POP_BACK_STACK_INCLUSIVE);. But there is no view with that id.
Just use popBackStack(). Fragment4 --> Fragment2 ( hosting fragment3) --> Fragment1 ( hosted by the activity).
If you want Fragment4 to Activity hosting Fragment1 don't add Fragment4 to the back stack.
Note : In case you want nested fragments you need to use getChildFragmentManager(). https://developer.android.com/about/versions/android-4.2.html
Also note the discussion in the comments sections and the link posted by op Is this the right way to clean-up Fragment back stack when leaving a deeply nested stack?

Android handle data in Fragments on back button press

I have 2 main Fragments in my MainActivity
[A] , [B]
and Fragment [A] has 3 more Fragments
[1] , [2] , [3]
And Fragment [1] has also a Fragment and that Fragment also has one more Fragment and this chain goes on.
Now when we press Back button of device, we first check current Fragment in MainActivity and work as :
if (fragment!=null &&fragment.getClass()== Fragment3.class) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment tFragment = new Fragment2();
ft.replace(R.id.container, tFragment);
ft.commit();
}
But this isn't a right way to do so I don't get data of Fragment [1] which came from Fragment [A] using Bundle. Please provide a proper way to do this.
I have tried also :
getSupportFragmentManager().popBackStack();
It works for coming into previous Fragment but I cannot called onResume method of that Fragment.
So I wanna know how I can use Back pressed button to handle the data.

Categories

Resources