Since I had to do a custom menu for my application, I've made a fragment which act like an actionbar at the bottom of my app!
But I have some conflicts with the stack (when pressing the back button).
How should I program the following method?
public void changerContenu(int frameLayout, Fragment frag, boolean ajouterAuStack)
{
if(R.id.frameContent != frag.getId())
// * if the current displaying
// fragment in the layout is the same as the one that I received in param#2 (frag),
// then don't do anything.
{
ft = fragmentManager.beginTransaction();
ft.replace(frameLayout, frag);
if(ajouterAuStack)
ft.addToBackStack(null);
ft.commit();
}
}
I know my "if" doesn't make any sense right now, trying to figure out how to come to the desired result :( Right now, when I visit the fragment once (and it's pushed into the stack) I cannot revisit it using my button in my "home made actionbar" until I hit the back button a few times to clean the stack.
I only want to not duplicate items in my stack if I click few times the same button on my menu...
Thanks guys!
I want to understand the question better.
You have a fragment that acts like an action bar. If the fragment is already displaying, you don't want to do anything; otherwise, you want to display it. In what circumstances do you want to go Back, and what should happen?
As a note, a single actionbar at the bottom doesn't fit in with the typical Android design. Users may not understand how to use your app. I'm interested in knowing why the regular ActionBar doesn't work for you.
For future reference, I got it working that way:
public void changerContenu(int frameLayout, Fragment frag, boolean ajouterAuStack, String tag)
{
ft = fragmentManager.beginTransaction();
ft.replace(frameLayout, frag);
if(ajouterAuStack && (fragmentManager.getBackStackEntryCount() == 0
|| fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1).getName() != tag))
ft.addToBackStack(tag);
ft.commit();
}
Related
The scenario is this...I click on a button that loads the next fragment. While the animation is still going I hit the recent apps button. After the recent apps screen is shown i return to my app.
Then I see the two fragments drawn on top of each other. As if Android forgot to remove the previous fragment.
I click back to remove all fragments until I reach the first fragment loaded in this FragmentActivity. I log all the fragments I get from FragmentManager and it only shows one. But I still see two fragments drawn one on top of the other. The one that should have been removed is not responding to touch events and the other one responds as it should.
Is this an Android bug or my fault? Is there any way to fix this or prevent it from happening ?
It does not happen every time. This is how I load my fragments
public void loadNewFragment(AnimFragment newFragment, boolean addToSTack, boolean animate, String tag) {
if (newFragment != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.fragment_enter_from_right, R.anim.fragment_exit_to_left, R.anim.fragment_enter_from_left, R.anim.fragment_exit_to_right);
transaction.replace(R.id.fragment_container, newFragment, tag);
if (addToSTack) {
transaction.addToBackStack(tag);
}
int transactionId = transaction.commit();
newFragment.setTransactionId(transactionId);
}
}
and I remove them on back pressed with
getSupportFragmentManager().popBackStackImmediate();
In my opinion "below" fragment is onPause() state and it's still alive and visible.
Try to use white background on the root layout of the front fragment to avoid showing the below fragment. Moreover the root layout size (width and height) of the front fragment should be match_parent.
Check this site to understand Fragment lifecycle.
https://google-developer-training.gitbooks.io/android-developer-advanced-course-concepts/unit-1-expand-the-user-experience/lesson-1-fragments/1-2-c-fragment-lifecycle-and-communications/1-2-c-fragment-lifecycle-and-communications.html
I'm working on a application which has Single activity rest all fragments...
This issue i'm facing occurs occasionally.. like when ever i press back button from any of the fragment the previous fragment appears... but sometimes it happens that My activity shows blank screen with action bar present, and rest of the screen is blank instead of showing the fragment... Since this issue appears occasionally i'm not able to debug it also... Any idea why it happens so??
Here is the code fragment transaction..
private void loadFragment(Fragment fragment, int activityNumber) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction trnx = manager.beginTransaction();
trnx.replace(R.id.fragPage, fragment, "Current_Fragment");
if (activityNumber != FragmentActivityNumbers.HOME_ORDERNUM) {
trnx.addToBackStack(null);
}
trnx.commit();
}
I suggest to test if its the first fragment so you use Add instead of replace then you can use replace for the others fragments .
I have a problem that I've been dealing with for the last couple o days and don't seem to find an answer to it.
Description : I have a main activity which contains a navigation drawer. Each item of the navigation drawer (when clicked) creates a fragment. In that fragment, there is a listView of objects, which creates other fragments when clicked. In those fragments i have another listView of objects which opens other fragments. In other words, there series of fragment that open other fragment. Something like this:
http://s22.postimg.org/pddo5gsv5/backstack.png
In order to be able to get back to each fragment, I've implemented the addToBackstack("string") method.
My question is, how can I implement correct backstack for my application so that when i click a navigation Drawer item, all the fragments that have been added to backstack are cleared, without the one that the navigation Drawer item opens.
Any help would be appreciated. Thank you !
EDIT
Ok, it seems I managed to figure it out. Considering what advices i received from the replies, here's the solution I came up with:
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count != 0) {
FragmentManager.BackStackEntry backEntry = getFragmentManager()
.getBackStackEntryAt(
getFragmentManager().getBackStackEntryCount() - 1);
if (backEntry.getName() == NAVIGATION) {
finish();
} else
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
To put it in words: First, i added a backstack entry even for the top level fragments, given them a specific tag. The I have overridden the Activity's back button function so that when the last backstack entry is a top-level fragment to finish the activity (so that it not simply detach the fragment from activity, living it empty). Otherwise, if the last entry isn't an top-level fragment, execute a popBackStack.
PS: All non-top-level fragments are added to the backstack with a different tag then the top-level one. Also, i had to do a POP_BACK_STACK_INCLUSIVE in the navigation Drawer's click listener.
getFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Thank you all for the advices and hopefully this EDIT help other users.
You can use the following code to solve your problem:
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(fragment_tag)
.commit();
In order to make the code above work, you have to create the fragments dynamically. As hardcoded fragments cannot be replaced. To do that, you can create a container (FrameLayout etc.) which in our example has the id fragment_container. Then, the code above will add the fragment in the container dynamically. Finally, you have to pass as parameter in the addToBackStack method the fragment_tag. That means, that this transaction will be added in the back stack. And finally, in order to get it from the backstack you have to use the code below:
getFragmentManager().popBackStack(fragment_tag, FragmentManager.POP_BACK_STACK_INCLUSIVE));
The POP_BACK_STACK_INCLUSIVE flag, insures that "all matching entries will be consumed until one that doesn't match is found or the bottom of the stack is reached. Otherwise, all entries up to but not including that entry will be removed."
You can clear the fragment backstack by using something like:
fragmentManager.popBackStack("string", FragmentManager.POP_BACK_STACK_INCLUSIVE);
and then you can addToBackstack and commit as usual. More info.
A code snippet that shows the way I normally use it in navigation drawers:
FragmentManager fragmentManager = getSupportFragmentManager();
if(clearBackStack) {
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
if(!clearBackStack) {
ft.addToBackStack(null);
}
ft.commit();
I am facing a problem of overlapping fragments when i switch between tabs and attach fragments to a tab view
below is my code please help
public class FragmentManage extends Fragment implements ActionBar.TabListener {
private Fragment mFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_manage, container, false);
OnClickListener clickListener = new OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
switch(v.getId()) {
case R.id.imageBtnCategory:
if (mFragment == null){
mFragment = new FragmentCategory();
}
ft.replace(android.R.id.content, mFragment);
break;
case R.id.imageBtnManageKey:
if (mFragment == null){
mFragment = new FragmentKeys();
}
ft.replace(android.R.id.content, mFragment);
break;
case R.id.imageBtnChangePswd:
if (mFragment == null){
mFragment = new FragmentChangePwd();
}
ft.replace(android.R.id.content, mFragment);
break;
}
ft.commit();
}
};
ImageButton imageBtnCategory = (ImageButton) v.findViewById(R.id.imageBtnCategory);
ImageButton imageBtnManageKey = (ImageButton) v.findViewById(R.id.imageBtnManageKey);
ImageButton imageBtnChangePswd = (ImageButton) v.findViewById(R.id.imageBtnChangePswd);
imageBtnCategory.setOnClickListener(clickListener);
imageBtnManageKey.setOnClickListener(clickListener);
imageBtnChangePswd.setOnClickListener(clickListener);
return v;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mFragment = new FragmentManage();
ft.add(android.R.id.content, mFragment);
ft.attach(mFragment);
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(mFragment);
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
Just set a background color to your <fragment /> in XML file.
Solves the issue.
Well Setting up fragment background color is not a solution because fragment will be still in the activity stack which may consume memory.
Solution would be remove all views from your framelayout before adding any new fragment.
private void changeFragment(Fragment fr){
FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
fl.removeAllViews();
FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
transaction1.add(R.id.mainframe, fr);
transaction1.commit();
}
I may be very late to answer this question.
Note:
This answer may not be related to the above question, But hope it will help for some.
Sometimes, Fragment overlap issue occurs when we try to use the different type of fragments( i.e using support fragment's in few fragments and normal fragments in someother fragment )
Recently i faced the same problem in Navigation drawer.
By mistake, i used "import android.support.v4.app.Fragment;" in one fragment, And used "import android.app.Fragment;" in few other fragment.
Hope this will help for somebody..
fragment manager maintains the stack of all the previous fragments that are replaced sometimes the back stack fragments overlaps with the fragment we replaced, for me
fragmentManager.popBackStack();
works, we can do this in a loop too to pop all the fragments in the stack hope it helps, Thanks. Happy Coding :)
This is how I fixed it ..
Setting the background would remove the overlapping effect from the screen only if the layout is matched to fill screen
New fragments replaced on button clicks were not getting replaced on tab_selected or tab change action
following code fixed it for me
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// This is required since button click replaces fragment whose link is lost hence overlapping isuee was occuring
ft.replace(android.R.id.content, mFragment);
// On Tab Change remove old fragment views
ft.remove(mFragment);
}
Did you check your XML and see if the main layout is Frame Layout? If not then, use the Frame Layout instead. This will resolve overlapping issue. That's the only way to fix. I tried the "accepted" answer while searching for a solution for this problem and it didn't work.
Another problem can be related to using android.R.id.content as a container. I've just created FrameLayout and use id from there.
I also faced fragment overlapping issue.Here is how I solved it -
1) We need to add the first fragment with addToBackStack, so that it is retained in the stack -
FirstFragment firstFragment = new FirstFragment();
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).addToBackStack("first frag").commit();
2) While adding the second fragment, replace the first fragment rather then adding it.Since the first fragment was already added in the stack, so it will be present when you press back from second fragment -
SecondFragment secondFragment= new SecondFragment();
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack("second frag").commit();
3) Here is how back press can be handled, below code should be present in the parent Activity -
public void onBackPressed(){
if(getFragmentManager().getBackStackEntryCount() <= 1){
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
private void changeFragment(Fragment fr){
FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
fl.removeAllViews();
FragmentTransaction transaction1 =getSupportFragmentManager().beginTransaction();
transaction1.add(R.id.mainframe, fr);
transaction1.commit();}
when you have a overlap fragment, maybe your background of your fragment is transparent, you need put a android:background="#color/white"' inside your fragment propeties
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
and white you need put inside of the colors.xml
#FFFFFF in the rest folder.
I have sometimes the same problem, but my problem is not related to different fragment managers (getSupportFragmentManager(), getFragmentManager()). I think there is still another problem. In my case, when I open the navigation drawer, I always delete old fragments on every menu option, for example:
Fragment calendarFragment = context.getSupportFragmentManager().findFragmentByTag(FragmentTag.CALENDAR.name());
if (calendarFragment != null)
{
context.getSupportFragmentManager().beginTransaction().remove(calendarFragment).commit();
}
It's not possible to get into a sub menu without the navigation drawer, so the fragments are basically always removed. In some cases, after I remove and add a fragment again inside an Activity it suddenly overlaps with another (previous) fragment?! But why does the fragment manager suddenly finds previous fragments?
That can either mean that the fragment manager is buggy and it does not remove old fragments, or that something other is broken.
My thought is, that it's somehow the fault of Android Studio or any other adb development tool which is used by it. Why I think that is, because Android Studio sometimes seem to loose the instance of the running app. Probably this problem is somehow related to the same issue: Android Studio not deploying changes to app. I didn't figure out yet when this happens. What I know is that it can't be a programming issue, because it's not reproducible after I relaunched the app by Android Studio. I guess there are somehow any background processes hanging which causes multiple instances of Activities, Fragments, fragment managers and so on. Furthermore it's not just this bug. I saw a lot of strange behaviours in past which are similar to this one. (For example the behaviours suddenly disappeared when the app was not started by IDE).
It all has to do with the engineering behind the replace and the addToBackStack methods.
The replace method will actually do two things. Hide the existing fragment (let's say A) and add a new one (let's say B) in the container.
Adding that transaction to the back stack will do the opposite.
Remove B and add A.
So, the solution to your problem is
1. use addToBackStack method.
2. make sure that the reverse replacement of fragments is the correct order
The second suggestion is really important, because it is pretty often that at some point the current fragment is not removed and another one is added, which causes the two fragments showing at the same time.
Making the background color white solved it for me too. I think this is a bug or and implementation issue in the Android fragmentment manager. I was implementing my replace and popBackStack() correctly.
When I had a problem like this it appeared that I was adding one fragment with childFragmentManager and another with parent's fragmentManager, so check that you use same type of fragment manager.
I don't think implementing a white background is a safe solution although it may be convenient. Basically the problem occurs because fragment manager is confused about which fragment to pop.
backstack looks like this and thinks your on frag 4 1->2, 2->3, 3->4
but your actually on frag 6 for some reason so popbackstack goes
remove(4) add(3) <- now you have 3(new) and 6(left behind) blended together
To better control my navigation I keep track of my current/previous fragments and replace them like this. This allows my app to control fragment navigation.
if ( !(currentFragment instanceof Settings)) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, settings);
fragmentTransaction.addToBackStack(null);
previousFrag = currentFragment;
currentFragment = settings;
fragmentTransaction.commit();
}
Secondly, I believe the fragmentmanager.replace() method is a better alternative. Not sure if that is available to OP at the time.
Third, to handle the androids native back press you need to be able to scroll back indefinitely. Many people recommend not adding the first fragment to back stack by not using this line.
fragmentTransaction.addToBackStack(null);
However if that's the case you must check if its the first time the app has loaded. If its not and you exclude this line then your app will have these issues whenever you navigate through this fragment. I prefer to leave it in place and do the following instead.
Not sure if this is considered a good solution but it works very well.
1- get backstack count
2- remove all existing frags
3- keep track of you fragment objects
4- if its the last frag in the stack the user wishes to exit and since we added the main activity to the back stack we need to double pop
#Override
public void onBackPressed() {
int num = getFragmentManager().getBackStackEntryCount();
fl.removeAllViews();
super.onBackPressed();
if (currentFragment != previousFrag) {
currentFragment = previousFrag;
}else{
currentFragment = null;
}
if (num == 1){
super.onBackPressed();
}
I found simple and clean solution. For me problem was in execution fragment transaction in every call of onCreate() of my Activity.
Now I perform transaction only if savedInstanceState == null
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
// replace fragment
}
}
Instead of using fragment as the container for the fragments, use FragmentContainerView. That solved the issue for me
I am facing a problem of overlapping fragments when i switch between tabs and attach fragments to a tab view
below is my code please help
public class FragmentManage extends Fragment implements ActionBar.TabListener {
private Fragment mFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_manage, container, false);
OnClickListener clickListener = new OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
switch(v.getId()) {
case R.id.imageBtnCategory:
if (mFragment == null){
mFragment = new FragmentCategory();
}
ft.replace(android.R.id.content, mFragment);
break;
case R.id.imageBtnManageKey:
if (mFragment == null){
mFragment = new FragmentKeys();
}
ft.replace(android.R.id.content, mFragment);
break;
case R.id.imageBtnChangePswd:
if (mFragment == null){
mFragment = new FragmentChangePwd();
}
ft.replace(android.R.id.content, mFragment);
break;
}
ft.commit();
}
};
ImageButton imageBtnCategory = (ImageButton) v.findViewById(R.id.imageBtnCategory);
ImageButton imageBtnManageKey = (ImageButton) v.findViewById(R.id.imageBtnManageKey);
ImageButton imageBtnChangePswd = (ImageButton) v.findViewById(R.id.imageBtnChangePswd);
imageBtnCategory.setOnClickListener(clickListener);
imageBtnManageKey.setOnClickListener(clickListener);
imageBtnChangePswd.setOnClickListener(clickListener);
return v;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mFragment = new FragmentManage();
ft.add(android.R.id.content, mFragment);
ft.attach(mFragment);
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(mFragment);
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
Just set a background color to your <fragment /> in XML file.
Solves the issue.
Well Setting up fragment background color is not a solution because fragment will be still in the activity stack which may consume memory.
Solution would be remove all views from your framelayout before adding any new fragment.
private void changeFragment(Fragment fr){
FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
fl.removeAllViews();
FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
transaction1.add(R.id.mainframe, fr);
transaction1.commit();
}
I may be very late to answer this question.
Note:
This answer may not be related to the above question, But hope it will help for some.
Sometimes, Fragment overlap issue occurs when we try to use the different type of fragments( i.e using support fragment's in few fragments and normal fragments in someother fragment )
Recently i faced the same problem in Navigation drawer.
By mistake, i used "import android.support.v4.app.Fragment;" in one fragment, And used "import android.app.Fragment;" in few other fragment.
Hope this will help for somebody..
fragment manager maintains the stack of all the previous fragments that are replaced sometimes the back stack fragments overlaps with the fragment we replaced, for me
fragmentManager.popBackStack();
works, we can do this in a loop too to pop all the fragments in the stack hope it helps, Thanks. Happy Coding :)
This is how I fixed it ..
Setting the background would remove the overlapping effect from the screen only if the layout is matched to fill screen
New fragments replaced on button clicks were not getting replaced on tab_selected or tab change action
following code fixed it for me
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// This is required since button click replaces fragment whose link is lost hence overlapping isuee was occuring
ft.replace(android.R.id.content, mFragment);
// On Tab Change remove old fragment views
ft.remove(mFragment);
}
Did you check your XML and see if the main layout is Frame Layout? If not then, use the Frame Layout instead. This will resolve overlapping issue. That's the only way to fix. I tried the "accepted" answer while searching for a solution for this problem and it didn't work.
Another problem can be related to using android.R.id.content as a container. I've just created FrameLayout and use id from there.
I also faced fragment overlapping issue.Here is how I solved it -
1) We need to add the first fragment with addToBackStack, so that it is retained in the stack -
FirstFragment firstFragment = new FirstFragment();
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).addToBackStack("first frag").commit();
2) While adding the second fragment, replace the first fragment rather then adding it.Since the first fragment was already added in the stack, so it will be present when you press back from second fragment -
SecondFragment secondFragment= new SecondFragment();
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack("second frag").commit();
3) Here is how back press can be handled, below code should be present in the parent Activity -
public void onBackPressed(){
if(getFragmentManager().getBackStackEntryCount() <= 1){
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
private void changeFragment(Fragment fr){
FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
fl.removeAllViews();
FragmentTransaction transaction1 =getSupportFragmentManager().beginTransaction();
transaction1.add(R.id.mainframe, fr);
transaction1.commit();}
when you have a overlap fragment, maybe your background of your fragment is transparent, you need put a android:background="#color/white"' inside your fragment propeties
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
and white you need put inside of the colors.xml
#FFFFFF in the rest folder.
I have sometimes the same problem, but my problem is not related to different fragment managers (getSupportFragmentManager(), getFragmentManager()). I think there is still another problem. In my case, when I open the navigation drawer, I always delete old fragments on every menu option, for example:
Fragment calendarFragment = context.getSupportFragmentManager().findFragmentByTag(FragmentTag.CALENDAR.name());
if (calendarFragment != null)
{
context.getSupportFragmentManager().beginTransaction().remove(calendarFragment).commit();
}
It's not possible to get into a sub menu without the navigation drawer, so the fragments are basically always removed. In some cases, after I remove and add a fragment again inside an Activity it suddenly overlaps with another (previous) fragment?! But why does the fragment manager suddenly finds previous fragments?
That can either mean that the fragment manager is buggy and it does not remove old fragments, or that something other is broken.
My thought is, that it's somehow the fault of Android Studio or any other adb development tool which is used by it. Why I think that is, because Android Studio sometimes seem to loose the instance of the running app. Probably this problem is somehow related to the same issue: Android Studio not deploying changes to app. I didn't figure out yet when this happens. What I know is that it can't be a programming issue, because it's not reproducible after I relaunched the app by Android Studio. I guess there are somehow any background processes hanging which causes multiple instances of Activities, Fragments, fragment managers and so on. Furthermore it's not just this bug. I saw a lot of strange behaviours in past which are similar to this one. (For example the behaviours suddenly disappeared when the app was not started by IDE).
It all has to do with the engineering behind the replace and the addToBackStack methods.
The replace method will actually do two things. Hide the existing fragment (let's say A) and add a new one (let's say B) in the container.
Adding that transaction to the back stack will do the opposite.
Remove B and add A.
So, the solution to your problem is
1. use addToBackStack method.
2. make sure that the reverse replacement of fragments is the correct order
The second suggestion is really important, because it is pretty often that at some point the current fragment is not removed and another one is added, which causes the two fragments showing at the same time.
Making the background color white solved it for me too. I think this is a bug or and implementation issue in the Android fragmentment manager. I was implementing my replace and popBackStack() correctly.
When I had a problem like this it appeared that I was adding one fragment with childFragmentManager and another with parent's fragmentManager, so check that you use same type of fragment manager.
I don't think implementing a white background is a safe solution although it may be convenient. Basically the problem occurs because fragment manager is confused about which fragment to pop.
backstack looks like this and thinks your on frag 4 1->2, 2->3, 3->4
but your actually on frag 6 for some reason so popbackstack goes
remove(4) add(3) <- now you have 3(new) and 6(left behind) blended together
To better control my navigation I keep track of my current/previous fragments and replace them like this. This allows my app to control fragment navigation.
if ( !(currentFragment instanceof Settings)) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, settings);
fragmentTransaction.addToBackStack(null);
previousFrag = currentFragment;
currentFragment = settings;
fragmentTransaction.commit();
}
Secondly, I believe the fragmentmanager.replace() method is a better alternative. Not sure if that is available to OP at the time.
Third, to handle the androids native back press you need to be able to scroll back indefinitely. Many people recommend not adding the first fragment to back stack by not using this line.
fragmentTransaction.addToBackStack(null);
However if that's the case you must check if its the first time the app has loaded. If its not and you exclude this line then your app will have these issues whenever you navigate through this fragment. I prefer to leave it in place and do the following instead.
Not sure if this is considered a good solution but it works very well.
1- get backstack count
2- remove all existing frags
3- keep track of you fragment objects
4- if its the last frag in the stack the user wishes to exit and since we added the main activity to the back stack we need to double pop
#Override
public void onBackPressed() {
int num = getFragmentManager().getBackStackEntryCount();
fl.removeAllViews();
super.onBackPressed();
if (currentFragment != previousFrag) {
currentFragment = previousFrag;
}else{
currentFragment = null;
}
if (num == 1){
super.onBackPressed();
}
I found simple and clean solution. For me problem was in execution fragment transaction in every call of onCreate() of my Activity.
Now I perform transaction only if savedInstanceState == null
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
// replace fragment
}
}
Instead of using fragment as the container for the fragments, use FragmentContainerView. That solved the issue for me