Replacing fragment wrong order when not using addToBackStack - android

I have a menu where the user can click on different buttons and swap between different bottom bars.
When a user clicks button1 following happens:
setFragment(R.id.bottom_bar_container, new FooBottomBar());
When they click button2 it will call:
setFragment(R.id.bottom_bar_container, new BarBottomBar());
Heres the setFragment method:
private void setFragment(int layout, Fragment newFragment) {
String tag = newFragment.getClass().getCanonicalName();
Fragment fragment = getFragmentManager().findFragmentByTag(tag);
if (fragment == null) {
fragment = newFragment;
}
Log.d("Tag", "Replacing with " + tag);
getFragmentManager()
.beginTransaction()
.replace(layout, fragment, tag)
.commit();
}
This works overall well but if user spam clicks on both buttons something interesting can happen.
Logcat:
Tag: Replacing with com.example.FooBottomBar
Tag: Replacing with com.example.BarBottomBar
But in the UI I can see FooBottomBar even though the last replacement was BarBottomBar.
I found that if I add addToBackStack(null) the problem goes away but I don't want to have this on the back stack.
getFragmentManager()
.beginTransaction()
.replace(layout, fragment, tag)
.addToBackStack(null)
.commit();
I would like to know the reason for this issue and if there's any solution to it.

Use getChildFragmentManager() with commitNow() instead.
getChildFragmentManager()
.beginTransaction()
.replace(layout, fragment, tag)
.commitNow();

Related

Inflate fragment just once

So, I have this code inside a setOnClickListener:
helpFragment = HelpFragment.newInstance()
supportFragmentManager
.beginTransaction() // Começar a transição
.replace(R.id.container, helpFragment)
.addToBackStack(helpFragment.toString())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit() // Aplicar as alterações
}
But the problem is, every time I click the button a new instance of the fragment is instantiated. With that, for example, if I click 10 times in the button, I will have 9 fragments added to backstack and 1 visible. How can I create just one instance of the fragment? I have tried:
if (helpFragment == null)
But that obviously doesn't work...
Adding a Fragment to the back stack will retain fragments in the stack so that you can navigate back when needed.
You can still use the back stack but you have to check if the fragment is already added so that you don't have duplicated instances of the fragment in the stack.
E.g.
val helpFragment = HelpFragment.newInstance()
val isInBackstack = supportFragmentManager.findFragmentByTag(helpFragment.toString())
if (!isInBackstack) {
supportFragmentManager
.beginTransaction() // Começar a transição
.replace(R.id.container, helpFragment)
.addToBackStack(helpFragment.toString())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit() // Aplicar as alterações
}
If you use addToBackStack, it'll always save the fragments to the backstack. Remove that line to not add the fragment to backstack. addToBackStack is used when there are multiple changes to the transaction, then all the changes are added in stack, and pressing back button will then restore those transactions one by one.
helpFragment = HelpFragment.newInstance()
supportFragmentManager
.beginTransaction() // Começar a transição
.replace(R.id.container, helpFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit() // Aplicar as alterações
}
It is better to see whole codebase of your problem. You can solve it with Kotlin's lazy. Check out this topic

findFragmentById on back button becomes blank as size becomes zero

Here's my Flow/Structure:
Activity
Fragment
Same Fragment within it.
I have overriden removeCurrentFragment() method which does go back functionality by removing Fragment by ID as follows -
#Override
public void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager().findFragmentById(R.id.fragment);
if (currentFrag != null)
transaction.remove(currentFrag);
transaction.commit();
}
It seems, when this happens, as ID of both fragment is same, it creates blank view.
If more details are required, please feel free to ask in comments. I will edit question as per required details.
I thought it was related to remove fragment, But I made new fragment with separate XML, still I am having the same issue.
I have parent fragment with pagination (as I need horizontal page scroll) in it have the child fragment, when clicking on child fragment button new fragment is replaced so when it is removed the X and Y of the child fragment is also disturbed.
here is the before and after screenshot of the x and y axis of child fragment.
Before
After
can any one suggest what could be the issue?
You have to use a tag to load the Fragment, and then use that same tag again to remove it.
For example, to add the Fragment:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
fragmentManager.popBackStack(tag, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.setCustomAnimations(R.anim.enter, R.anim.exit);
ft.add(containerId, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
To remove it, again use the same tag:
if (fragmentManager.findFragmentByTag(currentTag) != null) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.remove(fragmentManager.findFragmentByTag(currentTag));
ft.commit();
}

Android: fragments in Activity: after popBackStack() the number of present fragments stills the same

In my Activity, I add the first Fragment (myFragmentA) in onCreate() method:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
.add(containerViewId, myFragmentA, fragmentTag)
.addToBackStack(null)
.commit();
In this first fragment, when I click on a Button, I add a new fragment (myFragmentB):
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
.replace(containerViewId, myFragmentB, fragmentTag)
.addToBackStack(null)
.commit();
All is great to this point.
When I catch back pressed from Activity:
#Override
public void onBackPressed() {
// >>> Just to prevent to keep the first fragment !!
if (getSupportFragmentManager().getFragments().size() > 1) {
getSupportFragmentManager().popBackStack();
}
}
Back pressed from myFragmentB > myFragmentA : OK
Back pressed from myFragmentA (just to verify there is no popback) : FAILED. myFragmentA is removed too! And I want to keep it always. I don't know why getSupportFragmentManager().getFragments().size() is equal 2!
Thanks for your helps guys!
If i correctly understood.
You want to use
getBackStackEntryCount()
instead of
getFragments().size()
Take a look at the docs: http://developer.android.com/reference/android/support/v4/app/FragmentManager.html
You see, your container activity gets added to the back stack by default. In your code you have written addToBackStack(null) for both the fragments, this will add your fragments to the back stack over and above your activity which gets added to the back stack by default. This explains why you are seeing size 2, one may be your activity and the other your fragment.

Fragment shared element transition with add() instead of replace()?

I am trying to make a shared element transition between fragments, everything works fine when using replace() to add the second fragment, however in the codebase add() is used a lot, but when using that, transition just skips to end values
Is it possible to have the transition between added fragments?
Thanks
#Override
public void onClick(View v) {
setSharedElementReturnTransition(TransitionInflater.from(getActivity())
.inflateTransition(android.R.transition.move));
FragmentB secondFragment = new FragmentB();
secondFragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity())
.inflateTransition(android.R.transition.move));
getFragmentManager().beginTransaction()
.add(R.id.container, secondFragment)
.addToBackStack(null)
.addSharedElement(imageView, imageView.getTransitionName())
.commit();
}
Try this
getSupportFragmentManager().beginTransaction()
.addSharedElement(myImage, "mytransition")
.add(R.id.recycler_view_container, myFragment2)
.hide(myFragment1)
commit();
worked for me
since the system isnt going through the onPause from the first fragment its not going to happen. becuase when you add a new fragment, the new fragment comes on the top of the old fragment.
but you can fake it though you will have more code !
there is a sample below:
https://github.com/Kisty/FragmentTransitionExample
and a video not compeletely related but helps you to get the idea:
https://www.youtube.com/watch?v=CPxkoe2MraA
Try add .detach() method for FragmentTransaction.
FragmentManager manager = activity.getSupportFragmentManager ();
Fragment currentFragment = manager.findFragmentById (CONTAINER_ID);
int intoContainerId = currentFragment.getId ();
manager.beginTransaction ()
.setTransition (FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.addSharedElement(view, transitionName)
.addToBackStack (withTag)
.detach(currentFragment)
.add(intoContainerId, newFragment, withTag)
.commit();

Weird behavior in Fragment Backstack

I have an Activity that handles my fragments. I created the following method to add/replace fragments and add them (or not) to the backstack:
public void startFragment(CCFragment fragment, boolean addToBackStack) {
final String fragmentTag = fragment.getClass().getSimpleName();
final FragmentManager fragmentManager = getSupportFragmentManager();
// If my fragment is already in the backstack, I don't want to add
// it again, but go back to it:
boolean fragmentPopped=false;
if(fragmentManager.findFragmentByTag(fragmentTag)!=null){
fragmentPopped=true;
fragmentManager.popBackStack(fragmentTag,0);
}
//If it is not, I want to add/replace it
if (!fragmentPopped) {
fragment.setFragmentDelegate(this);
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(CONTENT_VIEW_ID, fragment, fragmentTag);
if (addToBackStack)
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
This works fine, until the following scenario happens:
startFragment(F1, false); //nothing in the backstack
startFragment(F2, true); //F1 in the backstack
startFragment(F3, false); //F1 in the backstack
startFragment(F1, false); -> when I call this, it enters the "if" and popBackStack won't work, so my app stays at the F3 instead of going back to F1. If I press the back button, then the app goes to F1...
So what am I doing wrong here? I already checked if the names are being stored right.
ft.addToBackStack(tag);
I'm not certain on this, but when you add a frag to the back stack, I believe you have to tag it (again). In your code, you're not supplying a tag, but using null, so there's no tag to search for, and even if it would otherwise use the original tag, you're overwriting it with null.
Edit: Use the following to verify the name of your tags on the backstack match the tags you originally assigned. I still believe your null is overwriting them.
FragmentManager mgr = getFragmentManager();
BackStackEntry be = mgr.getBackStackEntryAt(mgr.getBackStackEntryCount()-1);
String tag be.getName();
System.out.println("tag " + tag);

Categories

Resources