Android back button brings wrong fragment from backstack - android

I'm writing an android application using a FrameLayout and Fragments as its component.
I have 3 fragments: CommunityFragment, TaskFormFragment, TaskFragment.
In CommunityFragment, user presses a button to create a task. Then TaskFromFragment replaces with CommunityFragment in the FrameLayout with addToBackStack. Because after that, I want to return to CommunityFragment with back button.
In TaskFormFragment, user presses create button to create the task. Then TaskFragment opens without addToBackStack because I don't want to show TaskFormFragment when back button is presssed.
All of them working perfect. When I press back button in TaskFragment, CommunityFragment is shown. However, after that point, if I open TaskFormFragment and press back button, it doesn't show CommunityFragment! Instead, it opens TaskFragment.
How this can happen? Here is my fragment transition code:
From CommunityFragment to TaskFormFragment:
TaskFormFragment newFragment = new TaskFormFragment();
Bundle args = new Bundle();
args.putLong("taskTypeId", taskTypeId);
args.putLong("communityId", community.getId());
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
From TaskFormFragment to TaskFragment:
TaskFragment newFragment = new TaskFragment();
Bundle args = new Bundle();
args.putLong("taskId", task.getId());
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, newFragment);
transaction.commit();
EDIT: I found the solution in this entry: Problems with Android Fragment back stack

I've found the solution in another post. I've added that methods into my Activity class which contains the FrameLayout:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
return false;
} else {
getSupportFragmentManager().popBackStack();
removeCurrentFragment();
return false;
}
}
return super.onKeyDown(keyCode, event);
}
public void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager().findFragmentById(R.id.detailFragment);
if (currentFrag != null)
transaction.remove(currentFrag);
transaction.commit();
}
The description and the solution of this problem is here:
Problems with Android Fragment back stack

Once the user presses back in Task fragment and it goes back to community fragment, you should clear your backstack. Your problem is that it is not cleared so when you press back you go to a previous transaction.
EDIT:
So before your community fragment is replaced run this
for(int i =0;i<fragmentmanager.getBackStackEntryCount();i++){
fragmentmanager.popbackstack();
}
See if that fixes it

Related

Navigating between two fragments on backpress

I am having trouble going back to previous fragment on backpress from current fragment.
I have Two fragments and i navigate to second fragment on click and when i try to click back from the second fragment, i want to go back to the previous fragment but instead the app exits on backpress. below is the code i am using..
Fragment1 calling second fragment
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
In second Fragment i have implemented an interface OnBackpress and over riding the below method
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() != 0) {
if(getFragmentManager().findFragmentByTag("UserActivity") != null){
Log.e("UserActivity",getFragmentManager().findFragmentByTag("UserActivity").toString());
getFragmentManager().popBackStack();
};
}
}
But on back press the app exits. Instead i want to go back to previous fragment. What mistake am i doing? please help. thanks
You need to add you first fragment to back stack properly, you are doing it wrong in your first part of the code.
Use the following code instead.
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity");
transaction.commit();
Also there is no need to add any code in your onBackPressed after above change.
First, you need to add your fragments to the backstack:
public static void addFragment(FragmentManager fragmentManager, Fragment fragment, int id){
fragmentManager.beginTransaction().add(id, fragment).addToBackStack(null).commit();
}
Then you need to override the onBackPressed, which is a method gets called whenever a user clicks the back button:
#Override
public void onBackPressed() {
super.onBackPressed();
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
button.setVisibility(View.VISIBLE);
}
}
please change to add() instead of replace() in your code..
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.add(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
This will solve your problem.

Replace Fragment and press back

Hi Following my code to show detail fragment from list fragment
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.FragmentContainer1, DealFragment.newInstance(dealItems, position, currentPage, totalCount)).addToBackStack(null).commit();
Now when I press back button I get new ListFragment.ListFragmnt state is not saved.
I referred to some stack questions but haven't got right answer
I tried below code but it causes issues when app goes in background and is killed by system(Like I am opening chrome from my detail view and when I go back from chrome my app is closed and minimised) FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.hide(getActivity().getSupportFragmentManager().findFragmentById(containerId));
ft.add(containerId, detailFragment);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
Any solution on this problem when I move to ListFragment to detail hot maintain state of detail fragment.
I have referred this link from stack overflow here is the link
I want functionality same as Gmail app when we go from list to detail and come back to list fragment. Scroll position and everything is maintained which is not happening in my case
Try this :
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
this.finish();
}
}
In your activity set the first fragment:
ListFragment listFragment = new ListFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.FragmentContainer1, listFragment );
transaction.addToBackStack(null);
transaction.commit();
Then in listfragment call details fragment:
DetailFragment detailFragment = new DetailFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.FragmentContainer1, detailFragment);
transaction.addToBackStack(null);
transaction.commit();

Remove fragment issue

I have three fragments :
A is my main fragment, B is a login fragment, successful login will enter C fragment.
When I click on back button, I need to move to Fragment A from Fragment C.
My issue is that, when I click on back button I still move on Fragment B from Fragment A.
How can I fix my issue?
Here is my switch fragment function:
public void switchFragment(Fragment fragment) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
transaction.addToBackStack(null);
transaction.commit();
}
A fragment(NewHomepage) to B(LoginFragment) fragment:
switchFragment(LogInFragment.newInstance());
This is my B fragment, it has the value logged to decide switch A fragment or not when it come from C fragment.
I think that issue must be here, when go back to A fragment and click back button want to quit the APP, I can see the logcat show 1=> and 2=> .
String logged = memberData.getUD_MBTYPENAME(); //get the value when login succeed
Log.d(TAG,"1=>"+logged);
//If UD_MBTYPENAME is not null,change to A fragment
if (!TextUtils.isEmpty(logged)) {
Log.d(TAG,"2=>"+logged);
((MainActivity) getActivity()).switchFragment(NewHomepage.newInstance());
}
Here is about my MainActivity about onKeyDown and switchFragment:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
quickDialog();//It's a alert dialog
return false;
}
}
return super.onKeyDown(keyCode, event);
}
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
transaction.addToBackStack(null);
transaction.commit();
}
Take a reference change the code like this , if I don't use transaction.addToBackStack(null); , the issue is still there , even though remove transaction.addToBackStack(null);
When I back to A , I have to click twice back to show the alert dialog, I don't know what happened when I click back first time in A fragment.
if (!TextUtils.isEmpty(logged)){
Log.d(TAG,"2=>"+logged);
hideFragment(LogInFragment.newInstance());
switchFragment(NewHomepage.newInstance());
}
public void switchFragment(Fragment fragment) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
//remove it will fix my issue , but I have to click back twice to show alert dialog , I don't know what happened click it first time in A fragment.
//transaction.addToBackStack(null);
transaction.commit();
}
public void hideFragment(Fragment fragment) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.hide(fragment);
transaction.commit();
}
remove hideFragment and use manager.popBackStack(); on switchFragment , the issue will be fixed.
Try
It will show fragment if it is already added.
Use fragmentTransaction.show method to re-use existing fragment i.e. saved instance.
public void switchFragment (Fragment oldFragment, Fragment newFragment, int frameId) {
boolean addFragment = true;
FragmentManager fragmentManager = getFragmentManager ();
String tag = newFragment.getArguments ().getString ("TAG");
Fragment fragment = fragmentManager.findFragmentByTag (tag);
// Check if fragment is already added
if (fragment != null && fragment.isAdded ()) {
addFragment = false;
}
// Hide previous fragment
String oldFragmentTag = oldFragment.getArguments ().getString (BaseFragment.TAG);
if (!tag.equals (oldFragmentTag)) {
FragmentTransaction hideTransaction = fragmentManager.beginTransaction ();
Fragment fragment1 = fragmentManager.findFragmentByTag (oldFragmentTag);
hideTransaction.hide (fragment1);
hideTransaction.commit ();
}
// Add new fragment and show it
FragmentTransaction addTransaction = fragmentManager.beginTransaction ();
if (addFragment) {
addTransaction.add (frameId, newFragment, tag);
addTransaction.addToBackStack (tag);
}
else {
newFragment = fragmentManager.findFragmentByTag (tag);
}
addTransaction.show (newFragment);
addTransaction.commit ();
}

Handle Back Button Key during Fragments

Actually the Problem is i just load a Fragment(let call be Fragment-A) From the Navigation Drawer now the Fragment-A call a Dummy Activity, and the Dummy Activity Load a Fragment-B than fragment-B call a Fragment C and the fragment-C call the Fragment-D..
Overall Above picture:
Fragment-A(call)-->Dummy Activity(load)-->fragment-B(call)-->fragment-C(call)-->fragment-D(call)
Now i have Some Question Regarding this:
Actually there is one button in Fragment D, when the button is invoke i have to go back to the Fragment-A
now During the fragment(B,C& D) load i have to handle the On Back Pressed..
means if user in fragment D than on back press, than Fragment-C is load and vice versa but when the user is on Fragemnt-B an invoke the On-back key than Fragment A is load
NOTE :
i have to handle Both Above Back key or System Back Key
I know i have to maintain the Fragment Stack but how can i pass the case one
Edit:
Actually the Fragment-A is the Part of Activity-(a) and the remaing Fragmnets(B,C&D) is the Part of Activity-(X)
Code:
Repo link : Code link
The above scenario can be solved by below..
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
finish();
}
If the button in the fragment D invoked, please call the function
getActivity().onBackPresses();
It will finish the current Activity..
You need to add the fragments in backstack as follows:-
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentA);
//No need to put fragment A in backstack
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentB);
ft.addToBackStack(null);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentC);
ft.addToBackStack(null);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentD);
ft.addToBackStack(null);
ft.commit();
Now, All your fragments are in backstack so if you press Back on fragmentD then fragmentC will be shown and on pressing Back in fragmentC, fragmentB will be shown and on pressing Back in fragmentB, fragmentA will be shown.
AS, you mentioned you have a special button in fragmentD which on pressing should take you on fragment A, So on clicking that button execute this code:-
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}

Backstack Fragment not appearing in front on Back button prerssed

I have gone through many stackoverflow question before writing this. i am so confused about this guy Backstack in fragment.
I have Added three fragment on the same container inside an Activity
Fragment 1 :
private void addLandingFragment() {
landingPageFragment = LandingPageFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Fragment 2 :
public void addIntrofragment() {
fragment2 = IntroFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
transaction.addToBackStack(fragment2.getClass().getName() );
transaction.commit();
}
Fragment 3 :
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Now what I want is when user presses back button on fragment 3 it should come on very first fragment so I have overrided the onBackPressed() method.
#Override
public void onBackPressed() {
manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );
}
but nothing happening on screen it keeps fragment 3 running.
UPDATE
When I am navigating from
fragment1 > fragment2
and presses back button on fragment2, I am coming to fragment1 but if move from
fragment1 > fragment2> fragment3
I am getting the stack entry count 1 on onBackPressed() method but on device screen it still shows fragment3. Now pressing back button again will exit me from app but fragment1 wont come on screen. So puzzling why it is happening ?
Any solution to achieve this.
calling replace() will remove the previous fragment, Fragment 1 should be called using replace(), and Fragment 2 & 3 should be called using add(), you should also add the last transaction to back stack (calling Fragment 3)
Like this:
Fragment 1:
private void addLandingFragment() {
landingPageFragment = LandingPageFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Fragment 2:
public void addIntrofragment() {
fragment2 = IntroFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction .hide(LandingPageFragment.this);
transaction.add( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
transaction.addToBackStack(fragment2.getClass().getName() );
transaction.commit();
}
Fragment 3:
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
fragmentManager.popBackStackImmediate(); // to remove fragment 2
transaction.add( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.addToBackStack(fragment3.getClass().getName() );
transaction.commit();
}
finally your onBackPressed should be like this:
#Override
public void onBackPressed() {
fragmentManager.popBackStackImmediate();
fragmentTransaction.show(LandingPageFragment.this);
}
therefore your onBackPressed will always pop the top fragment on the stack (Fragment 3), and since Fragment 2 was already popped before adding Fragment 3, then onBackPressed will display the very first fragment.
Thanks Silvia.H for you support. I have solved my problem and found it as the best possible solution for me.
The only mistake I did was, I did not add fragment3 in backstack
So the only changes required was
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.addToBackStack(ConnectFragment.class.getName() );
transaction.commit();
}
Now this makes you clear that in order to use popBackStack with name like
manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );
you have to keep that transaction in backstack from where you are actually pressing the back button.
I have made one more small change in onBackPressed() method which allows the app to exist when user presses back button on fragment1.
My onBackPressed() look like this now
#Override
public void onBackPressed() {
if( manager.getBackStackEntryCount() > 0 ) {
getSupportFragmentManager().popBackStack(
scoreTrackerIntroFragment.getClass().getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE );
}else {
super.onBackPressed();
}
}
Woop! Now I am clear about this "Backstack" guy.

Categories

Resources