Android handle data in Fragments on back button press - android

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.

Related

How to handle fragment backstack

I'm having problem with fragment. Lets try to understand my issue, I have two fragment A and B. When app start with main activity,i start fragment A as you can see :
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new MusicFragment())
.commit();
When i click on a button, it starts fragment B
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
Main problem is after starting fragment B,when i pressed back to go back to fragment A , Fragment A Recreated with new state.
I don' want to recreate fragment A. I only want to start fragment from old state where i left. How to fix it ?
Instead of calling the replace method you should be calling the add method with a subsequent call to addToBackStack with an argument of null. The add method adds the fragement to the stack with a null tag and calling the addToBackStack with an argument of null then the current fragment is stopped upon commit. If the method is not called then the current fragment is destroyed and recreated when coming back.
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
You can clearly find it in the documentation quote saying this:
If you don't call addToBackStack() when you perform a transaction that
removes a fragment, then that fragment is destroyed when the
transaction is committed and the user cannot navigate back to it.
Whereas, if you do call addToBackStack() when removing a fragment,
then the fragment is stopped and is later resumed if the user
navigates back.
Here are some points that need to be taken care while creating fragments.
Check the backstack if the fragment is already created.
If it was created previously pop it from the backstack and put it on top so that it is visible to the user.
If fragment is not present in backstack crate it and store it in backstack.
Create a method like below which will handle such situation.
private void openFragment(Fragment fragment_to_be_opened){
String fragment_to_be_opened_name = fragment_to_be_opened.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
// fetching the fragment if it is present in backstack
boolean fragment_allready_present = manager.popBackStackImmediate (fragment_to_be_opened_name, 0);
if (!fragment_allready_present){ //fragment is not present in backstack so create it and save the name in //backstack
FragmentTransaction fragment_trasition = manager.beginTransaction();
fragment_trasition.replace(R.id.fragment_container, fragment_to_be_opened);
fragment_trasition.addToBackStack(fragment_to_be_opened_name);
fragment_trasition.commit();
}
}
Now call this method from the activity to open a new fragment like
// create instance of fragment and pass it to the open fragment method
Fragment myFragment = new myFragment();
openFragment(myFragment);

Android popBackStack shows fragment not added to the backstack

MainFragment launches FragA that launches FragB that lunches FragC.
Back button press on FragB should go to FragA and back press on FragC should also go to FragA.
FragB is the only one where isToAddToBackStack is false.
childFragmentManager.commit {
replace(containerViewId, fragment, fragment::class.java.name)
if (isToAddToBackStack) {
addToBackStack(backStateName)
}
}
Whenever the back button is pressed on FragC, FragB is shown:
if (childFragmentManager.backStackEntryCount > 1) {
childFragmentManager.popBackStack()
return
}
What's the better way to achieve the navigation that I'm expecting?
Fragment transactions can involve two different types of tags. The one that most Android developers are familiar with is the Fragment tag, which you can use to find a specific Fragment in your FragmentManager later via findFragmentByTag(). This is useful for finding a Fragment when your application is in a particular state, but keep in mind that the Fragment needs to be added to your FragmentManager. If you have removed() or replaced() a Fragment and haven’t added it to the back stack, you won’t be able to find it.
The other type of tag is the BackStackRecord’s name passed into addToBackStack(). This name identifies a particular back stack record, which is a record of what occurred in a particular transaction. popBackStackImmediate() and its counterparts have variants that accept a back stack record name to pop the back stack to a particular state.
//fm is FragmentManager
// Fragment a is on the screen
Fragment a = new A_Fragment()
fm.beginTransaction()
.remove(null /*no fragments in R.id.content*/)
.add(R.id.content, aFragment, "fragment-a")
.commit();
// user wants to go from A to B
Fragment bFragment = new B_Fragment();
fm.beginTransaction()
.remove(fm.findFragmentById(R.id.content))
.add(R.id.content, bFragment, "fragment-b")
.addToBackStack("a")
.commit();
// user wants to go from B to C
fm.beginTransaction()
.remove(fm.findFragmentById(R.id.content))
.add(R.id.content, new C_Fragment(), "fragment-c")
.commit();

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.

Building fragment stack for One Activity Many Fragment App

My App has only one activity and lots of fragments.
In my activty's XML, I just have a FrameLayout on which I replace/add/hide/show various fragments.
Imagine Fragment A is the first fragment the user sees when they open the app.
Click something in Fragment A to launch Fragment B and click something in Fragment B to launch Fragment C.
So the navigation is can be illustrated as follows :
Fragment A --> Fragment B --> Fragment C
I want to launch the app and show Fragment C directly from notification.
However, how can I provide back navigation from Fragment C, as such clicking back would go to Fragment B and clicking back again go to Fragment A ?
i.e How can I inject the following stack structure ?
Fragment A <-- Fragment B <-- Fragment C
Yes, you can do this. Since support library v26 you can build the stack with fragments without significant cost.
In your activity make the following:
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentA())
.addToBackStack("fragmentA")
.setReorderingAllowed(true)
.commit();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentB())
.addToBackStack("fragmentB")
.setReorderingAllowed(true)
.commit();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentC())
.addToBackStack("fragmentC")
.setReorderingAllowed(true)
.commit();
Keep in mind that FragmentA and FragmentB will behave in a bit different way after pressing back on FragmentC due to setReorderingAllowed. onCreateView won't be called for FragmentA and FragmentB after they were added to stack, only in FragmentC onCreateView will be called. For FragmentA and FragmentB only onCreate will be called.
What you can do is -
Use a notification intent in which you pass a string. In your main activity if you receive that string make a fragment stack of A, B and C.
Else if you don't get the intent just continue your flow as it is.

Back key to pop the Fragment shows overlapping fragments

I created a sample app to test this overlapping issue.
I have a fragment type, Fragment1, and I create a new instance of Fragment1 and add it to a FrameLayout in my activity at runtime. I add the fragment with the help of a few buttons.
Note: I have given each new instance of Fragment1 a different number(#1, #2, #3, etc.) to display on the UI to help me figure out which fragment I am viewing.
So.. here is what I do:
Click on Button 3, create new instance of Fragment1 and add it to Frame1.
Click on Button 4, create new instance of Fragment1 and add it to Frame1 and add it to the fragment backstack.
Repeat 1 and 2.
Repeat 1 and 2.
Now, I have fragments in this order: 1(#1),2(#2),1(#3),2(#4),1(#5),2(#6).
I press the back key when viewing fragment #6.
Back key press, UI displays (#5).
Back key press, UI displays (#3 AND #5),
Back key press, UI displays (#1, #3, AND #5)
It seems fragments are getting displayed ON TOP of each other.
WHY? Is there an overlapping issue? How can I clear out this overlapping issue. I thought this would be an issue on the compatibility library... but it is also on 3.0.
Code for adding fragments:
public int doFragmentChange(int cont1, Fragment frag1, String tag1, int cont2, Fragment frag2, String tag2,
boolean addToStack, String stackTag) {
FragmentManager fm = getFragmentManager();// getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (frag1 != null) {
ft.replace(cont1, frag1, tag1);
}
if (frag2 != null) {
ft.replace(cont2, frag2, tag2);
}
// add fragment to stack
if (addToStack)
ft.addToBackStack(stackTag);
return ft.commit();
}
If you perform two add calls one after the other (two commit calls) then yes the fragments will appear overlaid, one on top of the other effectively.
So (for new example) if say you replace frag1 with frag2 and then frag3 with frag4 in the same frame with no backstack transaction then I would expect frag2 and frag4 to be overlaid.
Furtheremore there is also a potential issue in your chaining of replace. You should call a separate commit for each. See Android — Replace Fragment Back Stack With New Stack?.
Just override the onBackPress() or onKeyUp and remove the top fragment.

Categories

Resources