I'm aiming for the following behavior.
When I am on my main activity,
If I navigate into fragment 1,
and from there, navigate into fragment 2,
then when I hit the phone's back button,
because I am on fragment 2 I am returned to the home screen, and not fragment 1.
If I had a separate button on the page, this behavior would be very easy, as I could just do:
Button.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
FragmentManager fm = getFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
I'm running into difficulties because I need to use the phone's own back button. I've read that the OnButtonPressed() event is only usable by an activity, not a fragment, and moving this kind of logic into the activity is proving difficult!
How can I achieve the behavior I'm after?
Just track the backstackcount and you can do whatever you want on the basis of count :
#Override
public void onBackPressed() {
manageBackStack();
}
private void manageBackStack() {
switch (getSupportFragmentManager().getBackStackEntryCount()) {
case 1:
//Do when count is 1
break;
case 2:
//Do when count is 2
break;
default:
finish();
}
}
Hope it will help :)
When you are adding the fragment you need to add the transaction to back stack. That means you want this transaction to be reversed when back button is pressed.
Please use the below code :
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
You can find more details in :
https://developer.android.com/training/implementing-navigation/temporal.html
Related
My MainActivity contains a Navigation Drawer with two fragments. The first fragment is loaded automatically when the app starts. I want the app to switch from fragment two to fragment one when the back button is pressed or if the first fragment is added then exit the app. I am adding the fragmentTransaction of the first fragment to a stack and then calling popBackStack in my onBackPressed method. However the behaviour is pretty weird.
When I'm on the first fragment the application should exit (ie, execute super.onBackPressed) however when on the first fragment and pressing back the first fragment is removed from the fragmentholder leading to a blank screen and then on pressing the second time the app closes.
When I'm on the second fragment nothing happens when the back button is pressed the first time and on pressing the back button a second time the app closes. Here's the relevant code from the MainActivity.java
#Override
public void onBackPressed() {
if (musicService.isPng()) moveTaskToBack(true);
if (getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStack("returnFragment", 0);
else super.onBackPressed();
}
private void loadSelection(int i) {
navList.setItemChecked(i, true);
switch (i) {
case 0:
FirstFragment firstFragment = new FirstFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragmentholder, firstFragment)
.addToBackStack("returnFragment")
.commit();
break;
case 1:
SecondFragment secondFragment = new SecondFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragmentholder, secondFragment)
.commit();
break;
case 2:
musicService.removeNotification();
musicService.stopSelf();
MainActivity.this.finish();
}
}
loadSelection(0) is called in the onCreate of the MainActivity
Unlike given in the code, I have tried various modes of implementing the popBackStack() method but all of them lead to the same result. Just to add I don't want to implement a workaround since there are only 2 fragments since I am already working on adding new fragments.
try this,
call method .addToBackStack("returnFragment") while loading second fragment and remove it from first transaction.
I am developing an android in which when I pressed device back button I go to previous fragment. What I want to achieve is that when I pressed device back button I don't want to go to previous fragment. How can I achieve that?.
You must be doing calling addtobackstack("name") while adding or replacing the fragment.Remove this function before calling next fragment you wont go back to previous fragment for further desc
Do not add that fragment to backstack of the new fragment you're calling. Look at the below example I've used to explain you how this works.
To make that fragment come again, just add that fragment to backstack which you want to come on back pressed,
Eg:
btnSignIn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new LoginFragment();
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack("SignupFragment");
ft.commit();
}
}
});
In the above case, I m opening a LoginFragment when signIn button is pressed, right now am in SignupFragment. So if I call addToBackStack(TAG), TAG = "SignupFragment", then when back button is pressed in LoginFragment, we come to SignUpFragment.
Happy Coding!
As title says, do anyone know a way how to implement OnBackPressed functionality, just like in Activity, but in Fragment View?
It does not work when I use onKey, onKeyDown or onBackPressed in Fragment - app is closing. I would like to execute specific code when back button is pressed, because in one of fragments I have ListView, which is filled with data depending on user actions.
So when back is pressed I would like to modify values of variables ("categories" and "part"), to fill ListView with specific data (so modify some values because user clicked something, and refresh this ListView), giving a feeling that user is going back (from parts, to categories and to close the app).
But as I mentioned, when I use onKey, onKeyDown or onBackPressed, app is closing... For instance when I include in my Fragment class:
public void onBackPressed() {
Toast.makeText(getActivity(), "AAAA", Toast.LENGTH_LONG).show();
}
Toast does not appear. With "onKeyDown" and "onKey" - the same situation... What am I doing wrong here, any ideas?
To answer your very first sentance:
as title says, do anyone know a way how to implement OnBackPressed
functionality, just like in Activity, but in Fragment View?
To make the back-button work with fragments you have to add them to the backstack. That should trigger the function you want.
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Finally, got it.
I had to, in my "ActionBarActivity" from method "onNavigationDrawerItemSelected" move declaration of "Fragment newFragment" to outside of this method, to make it available in whole class. Then I had to include "OnBackPressed" in my "ActionBarActivity" like this:
#Override
public void onBackPressed() {
if (!newFragment.onBackPressed()) {
super.onBackPressed();
}
}
And finally, in my Fragment I included also onBackPressed:
public boolean onBackPressed() {
if (part != -1) {
part = -1;
toAdd = "" + category + "_";
updateList();
return true;
}
return false;
}
And it works just like I wanted. When I push back, and when variable "part" in my Fragment is not -1, then it is executing operations defined above, returning true to "ActionBarActivity" so the app is not closing. But when, in my Fragment, variable is -1, then onBackPressed app is going back to main view, and again when user is pushing back, app is closing. That's what I wanted!
Thank You all for the help!
#Override
public void onBackPressed() {
super.onBackPressed();
Intent register = new Intent(PollCreateCommunities_Activity.this, PollActivity.class);
startActivity(register);
finish();
}
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
Intent register = new Intent(PollCreateCommunities_Activity.this, PollActivity.class);
startActivity(register);
return true;
}
return (super.onOptionsItemSelected(menuItem));
}
I have 4 fragment in my android app :
let's say A B C D where they 4 are fragments called in 1 activity. When I go from A to B and from be to C I want the back button to bring me to B and to A if I press again. But instead the back button forwards me to the previous activity.
I've read that the back button need to explicitely be handled as for fragments and I saw that code :
FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();
fragment.getView().setFocusableInTouchMode(true);
fragment.getView().setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
return true;
}
return false;
}
} );
The problem is that I'm not using any FragmentTransaction. Here is how I call my Fragments :
private void displayView(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
/*case 1:
fragment = new ContactsFragment();
break;*/
case 2:
fragment = new ContactsFragment();
break;
case 3:
fragment = new SitesFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
}
How can I use that back stacking with my code please ?
Thank you for your help in advance !
By calling .beginTransaction(), you are actually using a FragmentTransaction. The type itself is just not explicitly mentioned in your example. You can simply call addToBackStack() on the transaction to add the transaction to the fragment manager's back stack:
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).addToBackStack(null).commit();
Edit:
As Larry pointed out, adding to the fragment manager's back stack will automatically handle going back if your structure is as simple as A>B>C>D. If, for any reason, you need to manually handle the behavior of popping the backstack, you can use these instructions below:
In your activity, override onBackPressed() and call getFragmentManager().popBackStack(); Note: that you will need to know which fragment you are currently displaying so that you can safely call popBackStack on B, C, and D but if you are on A, you will want to (most likely) exit the activity. (Alternatively, you could only pop the back stack if there are items in it. For that, check if (getFragmentManager().getBackStackEntryCount() > 0)
Here's how your full fragment transaction code should look:
// the tag here is if you need to know which fragment is loaded, later
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment, tag).addToBackStack(null).commit();
Then, the back handler:
#Override
public void onBackPressed()
{
if (someCriteriaToDetermineIfBackStackShouldBePopped)
{
getFragmentManager().popBackStack();
return;
}
// this fragment is A (or something else) - let the parent handle the back press
// which will finish the activity
super.onBackPressed();
}
If you need help detecting which fragment is currently loaded, this should get you started: get currently displayed fragment
You need to use the FragmentTransaction to add/replace the new fragment, add it to the back stack, then commit. You do not need to handle the BACK button yourself unless you wish to override the default behavior. Adding it to the back stack in the FragmentTrasnaction before you commit will automatically pick up the desired BACK button support.
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.