I want to go back to another fragment by pressing the back button. I already read, that the addToBackStack (String tag) should help but it didn't really work.
Here is what I'm doing when switching fragments.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.content_frame, new MainFragment());
ft.addToBackStack("Mainfragment");
ft.commit();
So now, the Fragment opens, and starts an AsyncTask where a loading circle appears. After the loading the data gets displayed. When I now press the back button once, the fragment goes back to the start of the AsyncTask where the loading circle is created. But the AsyncTask doesn't continue. When I press the back button again, the app closes.
I tried to add onBackPressed but it just told me, that this won't work in a Fragment. What would be the best way to go here?
Edit for clarification:
There's no error. It's just not working. It is like I don't even have the line addToBackStack –
I had the same situation before and I ended up with this solution. When you add or replace the Fragments, you need to add it to the backStack with a unique name. Then when the back button is pressed you can see which fragment was the active one with the method below inside the FragmentActivity that you created the Fragment.
private String getCurrentFragmentName() {
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
String fragmentName;
if (backStackEntryCount > 0) {
fragmentName = getSupportFragmentManager().getBackStackEntryAt(backStackEntryCount - 1).getName();
} else {
fragmentName = "";
}
return fragmentName;
}
and in on onKeyDown() method do the following.
if (keyCode == KeyEvent.KEYCODE_BACK && getCurrentFragmentName().equals("your fragment name")) {
// Handle back press for this case.
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK
&& getCurrentFragmentName().equals("your another fragment")) {
// Handle back press for another Fragment
return true;
} else {
return super.onKeyDown(keyCode, event);
}
And this is the Place how I add the Fragment with backStack
transaction.addToBackStack("Your Fragment Name");
Related
I want to add to my android application back button listener which use popBackStack with unique values.
For example, I have fragments 1,2,3,4,5 and i visit them in order 1->2->3->2->3->4->3->5->3.
If I am in fragment 3 at end of queue, back button should back me to fragment 5, in this fragment back button should back me to fragment 4, in this to fragment 2 and in this to fragment 1 (3->5->4->2->1).
I have code, which works, but click on back button return me to previous fragment in this queue (3->5->3->4->3->2->3->2->1).
view.setOnKeyListener((view1, keyCode, keyEvent) -> {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (popDone) {
popDone = false;
return true;
} else {
if (getActivity().getSupportFragmentManager().getBackStackEntryCount() > 0) {
popDone = true;
getActivity().getSupportFragmentManager().popBackStack();
} else {
getActivity().finish();
}
return true;
}
}
return false;
});
It's not problem for your back action, but adding fragment. Read off document about using fragment. I suppose you are adding to backstack every fragment with no sense. Remove this line in your FragmentTransaction, whenever you don't need back stack fragmentTransaction.addToBackStack(null);
Man, adding all fragments into backstack and not reusing it - it's bad practice. When you need to open fragment you can check it in backstack.
I do it like this:
private void showFragmentIfNeeded(Fragment fragment) {
if (fragmentManager.findFragmentByTag(CURRENT_FRAGMENT_TAG) != null)
fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(CURRENT_FRAGMENT_TAG)).commit();
if (fragmentManager.findFragmentByTag(fragment.getClass().getSimpleName()) != null)
fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag(fragment.getClass().getSimpleName())).commit();
else
fragmentManager.beginTransaction().add(R.id.fragment_container, fragment, fragment.getClass().getSimpleName()).commit();
CURRENT_FRAGMENT_TAG = fragment.getClass().getSimpleName();
}
This question already has answers here:
White screen after going back through Fragments
(2 answers)
Closed 6 years ago.
I have a MainActivity, it has a lots of Fragment under it.
I set the return mechanism transaction.addToBackStack(null);
The function like this:
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
transaction.addToBackStack(null);
transaction.commit();
}
My issue is when I click the back button to the end, the FrameLayout is white
I tried to add
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mainFrame==null)
return super.onKeyDown(keyCode, event);
}
}
It's not working. How do I avoid this white screen when I call back the Fragment to the end ? Any help would be great!
I took #ReazMushed's suggestion and changed like this:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() ==1) {
finish();
}else{
super.onBackPressed()
}
}
And the white screen problem is gone!
From your question what I've understood is, you have a set of Fragment which is launched one after one and when you press the back button, they disappears one after one. When the first Fragment reaches and you click the back button again, it shows a white screen.
If I'm correct, you might have to track if the first Fragment is reached and then finish the Activity.
Implement the onBackPressed function in your MainActivity. You might consider doing something like this.
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
getSupportFragmentManager().popBackStack();
else
finish(); // Finish the activity
}
I've got an Android application which is working fine, but I've found an annoying bug which I don't know what else do to solve it.
My application has a single Activity (call it HomeActivity; well, plus the Preferences Activity) and lots of Fragments. HomeActivity manages the replacement of every Fragment using this method (found in this thread and especially looking into the following comment):
public void switchFragment(Fragment pFragment, String pTagFragment){
String backStateName = pTagFragment;
boolean fragmentPopped = mFragmentManager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.replace(R.id.content_frame, pFragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
To replace a Fragment, what I do is the following:
switchFragment(new FragmentEuskalmet(), FragmentEuskalmet.FRAGMENT_NAME);
Here it's the problem: I navigate through several Fragments (say, 3 of them). Then, I wanna go back, so I press back 2 times. When I arrive to the last within the stack, a white screen is shown (i.e. white is shown in the place where the Fragment should be). The odd thing is that if I do a long press to my home button to show the recent apps and I choose again my application, the fragment gets loaded correctly.
I assume there might be something within my switchFragment method, e.g. it may be any issue related to the backStack. One important detail is that I've got written the so called empty constructor in every Fragment.
Can anybody lend me a hand? I can provide further code pieces if anybody request them.
Edit:
I've considered compulsory to type my sss method:
#Override
public void onBackPressed(){
invalidateOptionsMenu();
if(CURRENT_FRAGMENT != FragmentMapa.FRAGMENT_NAME){//"com.ingartek.bizkaimove.ui.FragmentMapa"){
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerRightRelativeLayout);
}
if(mDrawer.isDrawerOpen(GravityCompat.START)){
mDrawer.closeDrawer(GravityCompat.START);
setToolbarSubtitle(mSubtitleAux);
}else{
setToolbarSubtitle(getString(R.string.app_name_subtitle));
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
//finish();
showExitDialog();
}else {
super.onBackPressed();
popFragment();
}
}
}
I think I should rewrite this part:
}else {
super.onBackPressed();
popFragment();
}
Solution:
As #Ajay Pandya suggested, I leave the onBackPressed() that way:
#Override
public void onBackPressed(){
invalidateOptionsMenu();
if(CURRENT_FRAGMENT != FragmentMapa.FRAGMENT_NAME){//"com.ingartek.bizkaimove.ui.FragmentMapa"){
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerRightRelativeLayout);
}
if(mDrawer.isDrawerOpen(GravityCompat.START)){
mDrawer.closeDrawer(GravityCompat.START);
setToolbarSubtitle(mSubtitleAux);
}else{
setToolbarSubtitle(getString(R.string.app_name_subtitle));
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
//finish();
showExitDialog();
}else{
mFragmentManager.popBackStackImmediate();
}
} else {
super.onBackPressed();
}
}
}
You can manage back stack and screen for exit like
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
This is because you are adding all your fragments programmatically. On pressing back buttons, you eventually remove the first fragment that you added as well.
The reason you get it back on launching the application is because you add the fragment again.
I would suggest overwrite your back button. Whenever you pop fragment, check to see that it's not your first fragment and then pop it.
I have a main activity that hosts a lot of fragments and a "home page" fragment. Every time I want to add a fragment, I will call this method inside the main activity.
public void addFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.fragmentContainer, fragment, "new_fragment");
ft.addToBackStack("new_fragment").commit();
}
Whenever the user presses the back button of the phone, I want the "home page" fragment to be the last page the user sees before he exits the application. How can I do that? I have tried this inside the onBackPressed() inside the MainActivity but it doesn't work (the back button is not working).
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentByTag("new_fragment");
//if fragment is home page fragment, exit application
//else pop the newest fragment or go to home page fragment
if (fragment == fragDefault) {
finish();
} else {
if(fm.getBackStackEntryCount() == 0){
//display home page fragment here
}
}
}
You can check your back stack when you press the back button/key.
When adding your 'home page' Fragment, don't put it to the back stack.
Add all other Fragments when needed and put them to the back stack.
When user press the back button/key, if the back stack is empty, exit app, else pop up Fragment from back stack.
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
finish();
}
else {
getFragmentManager().popBackStack();
}
Alternatively you might want to try this:
if (f instanceof HomePageFragmentClass) {
finish();
} else {
//f.dosomething();
}
*I have not tested it yet, let me know if it works.
I have only one activity and multiple fragments in my application.
Two main fragment A(left) and B(right).
Fragment A1 called from A
B1 called from B
B2 called from B1
All fragments have individual back buttons.
So when I press back button of fragment A1, it should go back to A, similarly when Back button from B2 is pressed, B1 appears and from B1 to B and so on.
How to implement this type of functionality?
public void onBackPressed()
{
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
}
I have implemented the similar Scenario just now.
Activity 'A' -> Calls a Fragment 'A1' and clicking on the menu item, it calls the Fragment 'A2' and if the user presses back button from 'A2', this goes back to 'A1' and if the user presses back from 'A1' after that, it finishes the Activity 'A' and goes back.
See the Following Code:
Activity 'A' - OnCreate() Method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activityA);
if (savedInstanceState == null) {
Fragment fragInstance;
//Calling the Fragment newInstance Static method
fragInstance = FragmentA1.newInstance();
getFragmentManager().beginTransaction()
.add(R.id.container, fragInstance)
.commit();
}
}
Fragment : 'A1'
I am replacing the existing fragment with the new Fragment when the menu item click action happens:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_edit_columns) {
//Open the Fragment A2 and add this to backstack
Fragment fragment = FragmentA2.newInstance();
this.getFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack(null)
.commit();
return true;
}
return super.onOptionsItemSelected(item);
}
Activity 'A' - onBackPressed() Method:
Since all the fragments have one parent Activity (which is 'A'), the onBackPressed() method lets you to pop fragments if any are there or just return to previous Activity.
#Override
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
}
else {
getFragmentManager().popBackStack();
}
}
If you are looking for Embedding Fragments inside Fragments, please refer the link: http://developer.android.com/about/versions/android-4.2.html#NestedFragments
#trueblue's answer got me going with one minor but annoying issue. When there is only one fragment on the backstack and you press back button, that frame is removed and the app remains active with a blank screen. User needed to press back button one more time to exit the app. I modified the original code to the following in order to handle this situation
#Override
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
}
else if(getFragmentManager().getBackStackEntryCount() == 1) {
moveTaskToBack(false);
}
else {
getFragmentManager().popBackStack();
}
}
When there is only 1 fragment in the backstack, we are basically telling android to move the whole app to back.
Update (and probably a better answer)
So after doing some more reading around this, I found out that you can add fragment manager transactions to back stack and then android handles back presses automatically and in a desired way. The below code snippet shows how to do that
Fragment fragment; //Create and instance of your fragment class here
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment).addToBackStack(null);
fragmentTransaction.commit();
fragmentTransaction.addToBackStack(null);
The last line shows how you add a transaction to back stack. This solves back press issue for fragments in most situations except for one. If you go on pressing back button, then eventually you will reach a point when there is only one fragment in the back stack. At this point, you will want to do one of the two things
Remove the activity housing the fragment from the back stack of the task in which activity is running. This is because you do not want to end up with a blank activity
If the activity is the only activity in the back stack of the task, then push the task in background.
In my case, it was the later, so I modified the overridden onBackPressed method from my previous answer to look like below
#Override
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() == 1) {
moveTaskToBack(false);
}
else {
super.onBackPressed();
}
}
This code is simpler because it has less logic and it relies on framework than on our custom code. Unfortunately I did not manage to implement code for first situation as I did not need to.
You have to implement your own backstack implementation as explained here.
You can call the popFragments() whenever you click the back button in a fragment and call pushFragments() whenever you navigate from one Fragment to other.
Just Do
getActivity().getFragmentManager().popBackStack();
Try this, Its Work for me.
public void onBackPressed() {
if (mainLayout.isMenuShown()) {
mainLayout.toggleMenu();
} else {
FragmentManager fm = getSupportFragmentManager();
Log.print("back stack entry", fm.getBackStackEntryCount() + "");
if (fm.getBackStackEntryCount() > 1) {
fm.popBackStack();
// super.onBackPressed();
// return;
} else {
if (doubleBackToExitPressedOnce) {
fm.popBackStack();
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Press one more time to exit",
Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 3000);
}
}
}
Back button will traverse in the order, in which Fragments were added to backstack. This is provided as a navigation function by default. Now if you want to go to specific Fragment, you can show it from backstack.
You can handle it by adding tag in the backStack. Check my answer here :
https://stackoverflow.com/a/19477957/1572408
hope it helps
#Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// replace your fragment here
return true;
}
return false;
}
});
}
// Happy Coding
If you press back image you have to create method first like this
private void Backpresses() {
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.contant_main, new Home()).commit();
}
then you have to call like this when you press back image..
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Backpresses();
}
});
It work fine for me.