I have a bug with replacing fragments inside FrameLayout container.
When app is started first time everything is Ok but when I hide app and then resume it fragments start overlap each other when FragmentTransaction.replace method is called
I've seen almost all stackoverflow questions about such issues but I can't resolve this issue
Code:
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
Add initial fragment:
getSupportFragmentManager().beginTransaction()
.add(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG)
.commit();
Replace:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
switch (menuItem.getItemId()) {
case R.id.request:
ft.replace(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG);
ft.commit();
return true;
case R.id.finished:
ft.replace(R.id.frame, FinishedFragment.newInstance(), FINISHED_FRAGMENT_TAG);
ft.commit();
return true;
case R.id.questions:
ft.replace(R.id.frame, QuestionsFragment.newInstance(), QUESTIONS_FRAGMENT_TAG);
ft.commit();
return true;
default:
return true;
}
Difficult to say as your code provides no context as to when it is run but I suspect the issue is when you are adding your initial fragment.
You are calling add instead of replace which will just add the new fragment on top of any existing ones. It is perfectly fine to use replace even if the container does not yet contain anything.
Fragments survive in the FragmentManager and are automatically re-attached to their container when the Activity restarts. The correct procedure is to check for an existing Fragment before adding a new one.
Add initial fragment
Fragment f=getSupportFragmentManager().findFragmentById(R.id.frame);
if (f==null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, RequestFragment.newInstance(), REQUEST_FRAGMENT_TAG).commit();
}
Also, it is helpful to make use of logging getSupportFragmentManager().getFragments().size(); whilst you are debugging. It lets you know how many fragments are currently in the FragmentManager and can highlight potential issues in your code. For example, if your count goes up every time you rotate the device, you are adding fragments and not checking for existing ones.
try to use FragmentTransaction.commitAllowingStateLoss() instead of using commit()
This sometimes happens because of the fragment background. Try setting solid background to all fragments in the stack so it's not empty or set to #null.
I wasn't calling the commit method at the end.
Related
I've been working for several months in an app. The version uploaded to the playstore works fine. Recently, doing some improvements, the whole app has started to work in a very strange way.
If you swith between fragments, after a while it does not inflate properly the fragments, putting always the content of the first one. So, if you switch the fragment, the action bar changes but the content is always the same (and you cannot interact with it).
Here is a quick video of the error https://streamable.com/9exa
I am going crazy as there is no log or trace whatsoever.
I am using the usual way of swithing fragments and the most intriguing part is that at the beginning everything works ok:
Fragment fragment = getSelectedFragment(index); // returns the desired fragment
FragmentManager fragmentManager = getFragmentManager();
//Pop backstack
for(int i = 0; i < fragmentManager.getBackStackEntryCount(); ++i) {
fragmentManager.popBackStack();
}
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack(null)
.commit();
Do anyone has any kind of idea what could be happening here? Thanks!
edit: I also have tried to clear the backstack in case it was the problem, but it doesn't change anything
solved: As I explain in my answer, I have discovered that is a problem related to a SwipeRefreshLayout. More information about this problem can be found at When switch fragment with SwipeRefreshLayout during refreshing, fragment freezes but actually still work
Ok, I found out the problem.
It seems that a SwipeRefreshLayout was the one causing all the problems. One of my fragments was using it, and after switching fragments a couple of times it gets stuck.
Removing it, or disabling it setEnabled(false) solves all the problems.
I hope it will help to anyone that is having the same problem!
Another thread in SO that refers to the same problem: When switch fragment with SwipeRefreshLayout during refreshing, fragment freezes but actually still work
What fragments are you using?
I had some strange behaviour using framework fragments, and i switched to V4 and everything worked fine
Please check this link: FragmentManager popBackStack doesn't remove fragment
I am using the following code in my activity for switching between fragments and it is working fine. My app's minSdkVersion is 15.
private void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.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 have an activity with a FrameLayout in it.
The activity should show four steps, and each step is a Fragment. When I want to go back-further, I don't want my fragments to be recreated. I would like to retain them and simply replace their view in my fragment.
I used to first create my Fragments and add them in the backstack like this:
Fragment step= new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.addToBackStack(null);
ft.commit();
notice that I don't show it, I simply create it and add to the backstack.
So, once I need one of my fragments to show, I add it (in this example I don't remove any fragment from the framelayout just because it's my first add):
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(R.id.my_frameLayout, step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
So: the problem is that I obtain a
Caused by: java.lang.IllegalStateException: Fragment already added: Frag1ActCompleteFragsCommTrack{410dcb20 #0 id=0x7f050041 -1}
But I think I can't add directly into my framelayout the first time, otherwise the next time I replace it, I could lose my fragment. Am I right? So.. what's the best practice for retaining fragments that could interchange each other in a framelayout?
Ladies and gentlemen, I did it!
If you add a Fragment, and you want it to be shown in a framelayout, remember to put it in the Fragment backstack. That's it! If you replace it in the framelayout with another one, no worries: you can put it back by finding it thanks to its tag.
It was easier than I thought actually
//step is an int describing the step associated to the fragment I wanna place
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.act_complete_track_frameLayout, f, ""+step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if(firstAttach)
ft.addToBackStack(null);
ft.commit();
imagine a fragment with tag "1" replaced through the code above by a fragment with tag "2". If I want to go back to step1, I reuse that code by obtaining my old fragment with getSupportFragmentManager().findFragmentByTag("1")
To be short, I thought that FragmentTransaction.replace removed the fragment from the backstack as well. That seems not to be the case (luckily)
You can always do something like fragmentManager.putFragment(yourFragment);
If I understand correctly, you are trying to add all the fragments but not show them until you are ready. FragmentTransaction.add() doesn't exactly do that though. It will also be shown after its added. You should use hide() after adding each fragment, and then later you can use show() to make it visible, and hide() again to make other fragments invisible.
Like this:
Fragment step = new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.hide(step);
ft.commit();
Then later:
Fragment step = getSupportFragmentManager().findFragmentByTag(""+onStepNr);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(step);
// may want to hide other fragments here
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
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
If it helps, what I want is similar to what is done in this google tutorial
But there a fragment is created prior to the transition. If I do that the transition works fine; but I can't use this approach
=====
Aiming to API 7+ I am just trying to have one Fragment visible in the whole screen and using a button (a drawn button, with an onTouch event) then alternate to a second fragment and viceversa.
But I either get a blank screen when I replace the first fragment with the second, or if I use fragmentTransaction.show and fragmentTransaction.hide; I can switch two times before I get blank screen. I dont want to have on backstack.
I am creating the fragments in MainActivity's onCreate:
DiceTable diceTable = new DiceTable();
Logger logger = new Logger();
fragmentTransaction.add(diceTable, DICETABLE_TAG);
fragmentTransaction.add(logger, LOGGER_TAG);
fragmentTransaction.add(R.id.fragment_container, logger);
fragmentTransaction.add(R.id.fragment_container, diceTable);
Then on one method (called from the fragments) I do the switch:
Logger logger = (Logger)fragmentManager.findFragmentByTag(LOGGER_TAG);
DiceTable diceTable = (DiceTable)fragmentManager.findFragmentByTag(DICETABLE_TAG);
if (diceTable.isVisible()) {
fragmentTransaction.replace(R.id.fragment_container, logger);
fragmentTransaction.commit();
fragmentTransaction.hide(diceTable);
fragmentTransaction.show(logger);
}
else if (logger.isVisible()) {
fragmentTransaction.replace(R.id.fragment_container, diceTable);
fragmentTransaction.commit();
fragmentTransaction.hide(logger);
fragmentTransaction.show(diceTable);
}
This is not how I should do this?
Blank screen when replacing fragments
Try to initialize fragments in that way:
private void initFragments() {
mDiceTable = new DiceTable();
mLogger = new Logger();
isDiceTableVisible = true;
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, mDiceTable);
ft.add(R.id.fragment_container, mLogger);
ft.hide(mLogger);
ft.commit();
}
And then flip between them in that way:
private void flipFragments() {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (isDiceTableVisible) {
ft.hide(mDiceTable);
ft.show(mLogger);
} else {
ft.hide(mLogger);
ft.show(mDiceTable);
}
ft.commit();
isDiceTableVisible = !isDiceTableVisible;
}
You are combining two different methods of changing which Fragment is shown:
Calling replace() to replace the contents of the container with a different Fragment
Calling hide() to remove a Fragment, then calling show() to show another Fragment.
Pick one method and stick with it. The Building a Flexible UI guide uses just the replace() method, so I would start by trying to remove all of your calls to show() and hide().
Also see Android Fragments: When to use hide/show or add/remove/replace? for a quick summary of when it might be beneficial to use hide/show instead of replace.
In case anyone has tried all of the already suggested answers and is still facing the issue, like I was a few moments ago, the problem may come from a different source than your fragments.
In my case, I was switching between fragments correctly, but the reason for the blank screen was that in each new fragment I was trying to asynchronously load images by starting a new Thread every time (something a bit like this) instead of the recommended AsyncTask, or better yet the newSingleThreadExecutor, since AsyncTask is deprecated.
I disturbed the background enough that the fragment was just not showing up unless I navigated to a different app then back.
So unless your mistake is similar to mine my suggestion might be kind of vague but try to see if anything is happening in your fragment that may be intensive on the resources (commenting out different pieces of code may help in investigating this).