I want to go back to the previous fragment.I tried many method like addtobackstack(null) and all. But I did not get the solution. My problem is when I click on the back button it goes to the home fragment. But I did not want it. I want that when I click on the back button it go to the previous fragment. Can anyone tell me how can I do this ?
This is my onActivityCreated() method :-
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if (i == KeyEvent.KEYCODE_BACK) {
getFragmentManager().popBackStack();
return true;
}
return false;
}
});
}
This is the first Fragment :-
Fragment fragment = new Packages();
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment).addToBackStack(null).commit();
This is the second fragment :-
Fragment fragment = new DeliveryFrag();
mContext.getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment).addToBackStack(null)
.commit();
This is the third Fragment :-
Fragment fragment = new paytm();
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment).addToBackStack(null)
.commit();
I am doing the get the view and apply set onClickListner on it. but the program not enter in this method. I don't know why? Please can anyone tell me what I am doing wrong?
You have to save fragment in stack using fragmentManager.addToBackStack(<fragment tag>).commit();. Then try to do getFragmentManager().popBackStack();
you should call this method in onResume. like this:
#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 (keyCode == KeyEvent.KEYCODE_BACK) {
getFragmentManager().popBackStack();
return true;
}
return false;
}
});
}
Make all public Fragment like so
public Fragment currentFrag = null;
public Fragment f1 = new Packages();
public Fragment f2 = new DeliveryFrag();
public Fragment f3 = new paytm();
Then, on the button where changing Fragment, fill your null currentFrag with the next one
#Override
public void onClick(View v){
if(currentFrag == null || currentFrag == f1){
//open second fragment code
currentFrag = f2;
}else if(currentFrag == f2){
//open third fragment code
currentFrag = f3;
}
}
then you override the onBackPressed() method in your main activity
#Override
public void onBackPressed()
{
if (currentFrag == f1){
super.onBackPressed() // close the app
}else if(currentFrag == f2){
//calling your first fragment code
currentFrag = null;
}else if(currentFrag == f3){
//calling your second fragment code
currentFrag = f2;
}
}
I hope this helps because even I'm getting a bit confused
worked for me....you can try this..... may help you...
write addToBackStack(null) before commit();
and write following code in your onBackPressed() method.
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 1) {
ApplicationLog.Log(TAG,"IN > 1");
fm.popBackStack(); //will redirect you previous visited fragment
}
else if(fm.getBackStackEntryCount()==1)
{
finish(); //will close application
}
I have an Activity with two Fragments (List & Details), in onCreate(), I start the List Fragment if savedInstance is null like so
public static final int CLIENT_LIST_FRAGMENT = 1;
public static final int CLIENT_DETAILS_FRAGMENT = 2;
private int currentFragment = 0;
if (savedInstanceState == null) {
//On first run, start the list fragment
if (currentFragment == 0) {
ClientListFragment listFrag = new ClientListFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
} else {
switch (currentFragment) {
case CLIENT_LIST_FRAGMENT:
addListFragment();
break;
case CLIENT_DETAILS_FRAGMENT:
addDetailsFragment(0);
break;
}
}
}
And here is the method that add the DetailsFragment and ListFragment as needed
private void addListFragment(){
ClientDetailsFragment listFrag = new ClientDetailsFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.addToBackStack("details")
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
}
private void addDetailsFragment(long companyId){
ClientDetailsFragment detailsFrag = ClientDetailsFragment.newInstance(companyId);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_client, detailsFrag, Constants.CLIENT_DETAILS_TAG)
.addToBackStack(null)
.commit();
currentFragment = CLIENT_DETAILS_FRAGMENT;
}
This works as expected except that when I click the back button from the Details Fragment, instead of taking me back to the List Fragment, it actually finishes the Activity. It goes back to the List Fragment for a split second and then finishes the host Activity and goes back to the calling Activity. How can I stop this behavior, after going through a lot of onBackpress related question on SO here is my overide of the onBackPressed
#Override
public void onBackPressed() {
if (currentFragment == CLIENT_DETAILS_FRAGMENT){
getSupportFragmentManager().popBackStackImmediate();
}else {
super.onBackPressed();
}
}
Thanks
Activity onBackPressed() should be:
For android.support.v4.app.Fragment
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 1)
getSupportFragmentManager().popBackStack();
else
finish();
}
For android.app.Fragment
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1)
getFragmentManager().popBackStack();
else
finish();
}
I usually check whether the current fragment instance belongs to the fragment that invoked onBackPressed(). This code is untested; it's just to give you an idea on how to proceed. I hope you are not calling this.finish() on this Activity.
#Override
public void onBackPressed() {
Fragment fragment = getSuportFragmentManager().findFragmentByTag(Constants.CLIENT_DETAILS_TAG);
if (fragment instanceof ClientDetailsFragment) {
getSupportFragmentManager().popBackStackImmediate();
}
else {
super.onBackPressed();
}
}
Let me know if that helps.
Good Lord, I was chasing the wrong shadow for two days. I was listening, handling and overriding the wrong event.
This SO question saved me Why is onBackPressed() not being called?
And the gist is "onBackPressed() is invoked when user clicks on a hardware back button (or on the 'up' button in the navigation bar), not the button in the action bar. For this one you need to override onOptionsItemSelected() method. Example:"
I was catching this event the fragment and calling getActivity.onBackpressed. When I stopped this, it became obvious to me that the onBackPressed is not being called. Here is my solution, may not be optimal but it works
if (item.getItemId() == android.R.id.home){
if (currentFragment == CLIENT_DETAILS_FRAGMENT){
getSupportFragmentManager().popBackStackImmediate();
currentFragment = CLIENT_LIST_FRAGMENT;
return true;
}
}
if (currentFragment == 0) {
ClientListFragment listFrag = new ClientListFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container_client, listFrag, Constants.CLIENT_LIST_FRAGMENT_TAG)
.commit();
currentFragment = CLIENT_LIST_FRAGMENT;
}
while changing this add to addToBackStack()
and,
change onBackPressed() like,
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 1) {
MainActivity.this.finish();
}
else {
getFragmentManager().popBackStack();
}
}
Hope, this will work.
I am trying to override onbackpressed method inside fragment . But it gives me syntax error that it should override a super method in interface. Why so? I have other methods like ondestroy also in my fragment class but no error. Why for this backpressed alone. I tried onkeydown also. Same error. Pasting below my code.
public TestClass extends Fragment implements Testinterface
{ #Override //error must override or implement supertype method
public void onBackPressed ()
{
if (check)
Do somethin
else
getActivity().finish ()
//super.onBackPressed () // error here if I use this
}
You have to implement on key down in fragment, check for key code. The onBackPress() method can be used in an Activity -- which is the logical parent of your fragment.
Try this:
frag.getView().setFocusableInTouchMode(true);
frag.getView().setOnKeyListener( new OnKeyListener(){
#Override
public boolean onKey( View v, int keyCode, KeyEvent event ){
if( keyCode == KeyEvent.KEYCODE_BACK ){
return true;
}
return false;
}
} );
You can propagate onBackPressed() to all your fragments,for that you need to create two classes with the following methods and then make all your activties and fragments inherit from them:
public class BaseActivity extends ActionBarActivity {
#Override
public void onBackPressed() {
boolean eventConsumed = false;
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment instanceof BaseFragment) {
eventConsumed = eventConsumed
|| ((BaseFragment) fragment).onBackPressed();
}
}
}
if (!eventConsumed) {
super.onBackPressed();
}
}
}
public class BaseFragment extends Fragment {
public boolean onBackPressed() {
return false;
}
}
Note that this code is using the support library, if you are not using it you need to do the appropriate changes.
Try to avoid using onKey in fragment. There is a better way.
For maintenance, I recommend you to use getBackStackEntryCount()
in Activity
final FragmentMananger fm = new getSupportFragmentManager();
#Override
protected void onCreate(Bundle b){
super.onCreate(b);
setContentView(R.layout.activity_main);
Fragment fragment = new SomeFragment();
// if you don't run on prior to Android 3.0 use getFragmentManager();
fm.beginTransaction().replace(R.id.frame_container, fragment).addToBackStack(null).commit();
// R.id.frame_container is the id of FrameLayout in activity_main.xml
}
#Override
public void onBackPressed(){
if(fm.getBackStackEntryCount() == 0){
finish();
}else{
super.onBackPressed();
}
}
I am working on a project and I need to be able to use the back button in each fragment to navigate between previous fragments, I have methods written to do so by using a back arrow in the action bar, however, I want to be able to use the same functionality on the back button pressed. I don't want to use the back stack. Is there a way to do this?
EDIT
Rather than using the back stack I want to be able to call the go back to previous method below when the user clicks the back button. I need to used the gobackpressed method within fragments. Is this possible? I hope this is clear and concise. Apologies for any confusion caused above.
Go Back to Previous
public void gobackToPreviousFragment(String preFragmentTag, Fragment preFragment){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.close_slide_in,R.animator.close_slide_out);
ft.show(preFragment);
//**BY REMOVING FRAGMENT, WHEN USER TRIES TO REVISIT, FRAGMENT IS BLACK**
ft.remove(fm.findFragmentByTag(Misc.currentContentFragmentTag));
ft.addToBackStack(null);
ft.commit();
Misc.currentContentFragmentTag = preFragmentTag;
createBar(preFragment);
}
Go Forward
public void gotoNextFragment(String nextTag, Fragment nextFragment){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.enter_slide_in, R.animator.enter_slide_out);
boolean newlyCreated = false;
if(nextFragment == null){
nextFragment = Fragment.instantiate(this, nextTag);
newlyCreated = true;
}
//hide current fragment
ft.hide(fm.findFragmentByTag(Misc.currentContentFragmentTag));
if(newlyCreated){
ft.add(R.id.content_frame, nextFragment, nextTag);
}
else{
ft.show(nextFragment);
}
ft.addToBackStack(null);
ft.commit();
Misc.currentContentFragmentTag = nextTag;
createBar(nextFragment);
}
These are how I navigate back and forth, and I'd like to be able to implement the go back method on the onBackPressed(). Does this make sense?
I didn't find any good answer about this problem, so this is my solution.
If you want to get backPress in each fragment do the following.
create interface OnBackPressedListener
public interface OnBackPressedListener {
void onBackPressed();
}
That each fragment that wants to be informed of backPress implements this interface.
In parent activity , you can override onBackPressed()
#Override
public void onBackPressed() {
List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
if (fragmentList != null) {
//TODO: Perform your logic to pass back press here
for(Fragment fragment : fragmentList){
if(fragment instanceof OnBackPressedListener){
((OnBackPressedListener)fragment).onBackPressed();
}
}
}
}
Why don't you want to use the back stack? If there is an underlying problem or confusion maybe we can clear it up for you.
If you want to stick with your requirement just override your Activity's onBackPressed() method and call whatever method you're calling when the back arrow in your ActionBar gets clicked.
EDIT: How to solve the "black screen" fragment back stack problem:
You can get around that issue by adding a backstack listener to the fragment manager. That listener checks if the fragment back stack is empty and finishes the Activity accordingly:
You can set that listener in your Activity's onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getFragmentManager().getBackStackEntryCount() == 0) finish();
}
});
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.w("a","")
}
})
In the fragment where you would like to handle your back button you should attach stuff to your view in the oncreateview
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.second_fragment, container, false);
v.setOnKeyListener(pressed);
return v;
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if( keyCode == KeyEvent.KEYCODE_BACK ){
// back to previous fragment by tag
myfragmentclass fragment = (myfragmentclass) getActivity().getSupportFragmentManager().findFragmentByTag(TAG);
if(fragment != null){
(getActivity().getSupportFragmentManager().beginTransaction()).replace(R.id.cf_g1_mainframe_fm, fragment).commit();
}
return true;
}
return false;
}
};
This works for me :D
#Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
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){
// handle back button's click listener
return true;
}
return false;
}
});}
You can try to override onCreateAnimation, parameter and catch enter==false. This will fire before every back press.
#Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
if(!enter){
//leaving fragment
Log.d(TAG,"leaving fragment");
}
return super.onCreateAnimation(transit, enter, nextAnim);
}
For a Fragment you can simply add
getActivity().onBackPressed();
to your code
I found a new way to do it without interfaces. You only need to add the below code to the Fragment’s onCreate() method:
//overriding the fragment's oncreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//calling onBackPressedDispatcher and adding call back
requireActivity().onBackPressedDispatcher.addCallback(this) {
//do stuff here
}
}
Use this:
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
}
super.onBackPressed();
}
This question already has answers here:
How to implement onBackPressed() in Fragments?
(58 answers)
Closed 6 years ago.
I have some fragments in my activity
[1], [2], [3], [4], [5], [6]
And on Back Button Press I must to return from [2] to [1] if current active fragment is [2], or do nothing otherwise.
What is the best practise to do that?
EDIT: Application must not return to [2] from [3]...[6]
When you are transitioning between Fragments, call addToBackStack() as part of your FragmentTransaction:
FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();
If you require more detailed control (i.e. when some Fragments are visible, you want to suppress the back key) you can set an OnKeyListener on the parent view of your fragment:
//You need to add the following line for this solution to work; thanks skayred
fragment.getView().setFocusableInTouchMode(true);
fragment.getView().requestFocus();
fragment.getView().setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
return true;
}
return false;
}
} );
I'd rather do something like this:
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
super.onBackPressed();
}
}
if you overide the onKey method for the fragment view you're gonna need :
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
Log.i(tag, "keyCode: " + keyCode);
if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
Log.i(tag, "onKey Back listener is working!!!");
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return true;
}
return false;
}
});
Use addToBackStack method when replacing one fragment by another:
getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).addToBackStack("my_fragment").commit();
Then in your activity, use the following code to go back from a fragment to another (the previous one).
#Override
public void onBackPressed() {
if (getParentFragmentManager().getBackStackEntryCount() > 0) {
getParentFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
If you want to handle hardware Back key event than you have to do following code in your onActivityCreated() method of Fragment.
You also need to check Action_Down or Action_UP event. If you will not check then onKey() Method will call 2 times.
Also, If your rootview(getView()) will not contain focus then it will not work. If you have clicked on any control then again you need to give focus to rootview using getView().requestFocus(); After this only onKeydown() will call.
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Toast.makeText(getActivity(), "Back Pressed", Toast.LENGTH_SHORT).show();
return true;
}
}
return false;
}
});
Working very well for me.
Create interfaces:
BackButtonHandlerInterface
public interface BackButtonHandlerInterface {
void addBackClickListener (OnBackClickListener onBackClickListener);
void removeBackClickListener (OnBackClickListener onBackClickListener);
}
OnBackClickListener
public interface OnBackClickListener {
boolean onBackClick();
}
In Activity:
public class MainActivity extends AppCompatActivity implements BackButtonHandlerInterface {
private ArrayList<WeakReference<OnBackClickListener>> backClickListenersList = new ArrayList<>();
#Override
public void addBackClickListener(OnBackClickListener onBackClickListener) {
backClickListenersList.add(new WeakReference<>(onBackClickListener));
}
#Override
public void removeBackClickListener(OnBackClickListener onBackClickListener) {
for (Iterator<WeakReference<OnBackClickListener>> iterator = backClickListenersList.iterator();
iterator.hasNext();){
WeakReference<OnBackClickListener> weakRef = iterator.next();
if (weakRef.get() == onBackClickListener){
iterator.remove();
}
}
}
#Override
public void onBackPressed() {
if(!fragmentsBackKeyIntercept()){
super.onBackPressed();
}
}
private boolean fragmentsBackKeyIntercept() {
boolean isIntercept = false;
for (WeakReference<OnBackClickListener> weakRef : backClickListenersList) {
OnBackClickListener onBackClickListener = weakRef.get();
if (onBackClickListener != null) {
boolean isFragmIntercept = onBackClickListener.onBackClick();
if (!isIntercept) isIntercept = isFragmIntercept;
}
}
return isIntercept;
}
}
In Fragment:
public class MyFragment extends Fragment implements OnBackClickListener{
private BackButtonHandlerInterface backButtonHandler;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
backButtonHandler = (BackButtonHandlerInterface) activity;
backButtonHandler.addBackClickListener(this);
}
#Override
public void onDetach() {
super.onDetach();
backButtonHandler.removeBackClickListener(this);
backButtonHandler = null;
}
#Override
public boolean onBackClick() {
//This method handle onBackPressed()! return true or false
return false;
}
}
Update
Provide custom back navigation
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This callback will only be called when MyFragment is at least Started.
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
// The callback can be enabled or disabled here or in the lambda
}
}
The most ideal way of doing this is found here:
Fragment: which callback invoked when press back button & customize it
public class MyActivity extends Activity
{
//...
//Defined in Activity class, so override
#Override
public void onBackPressed()
{
super.onBackPressed();
myFragment.onBackPressed();
}
}
public class MyFragment extends Fragment
{
//Your created method
public static void onBackPressed()
{
//Pop Fragments off backstack and do your other checks
}
}
#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){
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){
mDrawerLayout.closeDrawer(GravityCompat.START);
}
return true;
}
return false;
}
});
}
After looking at all solutions, I realised there is a much simpler solution.
In your activity's onBackPressed() that is hosting all your fragments, find the fragment that you want to prevent back press. Then if found, just return. Then popBackStack will never happen for this fragment.
#Override
public void onBackPressed() {
Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”);
if (fragment1 != null)
return;
if (getFragmentManager().getBackStackEntryCount() > 0){
getFragmentManager().popBackStack();
}
}
We created tiny library for handling back press across multiple fragments and/or in Activity. Usage is as simple as adding dependency in your gradle file:
compile 'net.skoumal.fragmentback:fragment-back:0.1.0'
Let your fragment implement BackFragment interface:
public abstract class MyFragment extends Fragment implements BackFragment {
public boolean onBackPressed() {
// -- your code --
// return true if you want to consume back-pressed event
return false;
}
public int getBackPriority() {
return NORMAL_BACK_PRIORITY;
}
}
Notify your fragments about back presses:
public class MainActivity extends AppCompatActivity {
#Override
public void onBackPressed() {
// first ask your fragments to handle back-pressed event
if(!BackFragmentHelper.fireOnBackPressedEvent(this)) {
// lets do the default back action if fragments don't consume it
super.onBackPressed();
}
}
}
For more details and other use-cases visit GitHub page:
https://github.com/skoumalcz/fragment-back
Or you could use getSupportFragmentManager().getBackStackEntryCount() to check what to do:
#Override
public void onBackPressed() {
logger.d("###### back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
// only show dialog while there's back stack entry
dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment");
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
// or just go back to main activity
super.onBackPressed();
}
}
If you manage the flow of adding to back stack every transaction, then you can do something like this in order to show the previous fragment when the user presses back button (you could map the home button too).
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStack();
else
super.onBackPressed();
}
For Those Who Use Static Fragment
In a case if you have a static fragment then It would be preferable.
Make an instance object of your fragment
private static MyFragment instance=null;
in onCreate() of MyFragment initialize that instance
instance=this;
also make a function to get Instance
public static MyFragment getInstance(){
return instance;
}
also make functions
public boolean allowBackPressed(){
if(allowBack==true){
return true;
}
return false;
}
//allowBack is a boolean variable that will be set to true at the action
//where you want that your backButton should not close activity. In my case I open
//Navigation Drawer then I set it to true. so when I press backbutton my
//drawer should be get closed
public void performSomeAction(){
//.. Your code
///Here I have closed my drawer
}
In Your Activity You can do
#Override
public void onBackPressed() {
if (MyFragment.getInstance().allowBackPressed()) {
MyFragment.getInstance().performSomeAction();
}
else{
super.onBackPressed();
}
}
Working Code:
package com.example.keralapolice;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
public class ChiefFragment extends Fragment {
View view;
// public OnBackPressedListener onBackPressedListener;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle args) {
view = inflater.inflate(R.layout.activity_chief, container, false);
getActivity().getActionBar().hide();
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
Log.i(getTag(), "keyCode: " + keyCode);
if (keyCode == KeyEvent.KEYCODE_BACK) {
getActivity().getActionBar().show();
Log.i(getTag(), "onKey Back listener is working!!!");
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
// String cameback="CameBack";
Intent i = new Intent(getActivity(), home.class);
// i.putExtra("Comingback", cameback);
startActivity(i);
return true;
} else {
return false;
}
}
});
return view;
}
}
I think the easiest way is to create an interface, and in the Activity check if the fragment is of the interface type, and if so, call its method to handle the pop. Here's the interface to implement in the fragment.
public interface BackPressedFragment {
// Note for this to work, name AND tag must be set anytime the fragment is added to back stack, e.g.
// getActivity().getSupportFragmentManager().beginTransaction()
// .replace(R.id.fragment_container, MyFragment.newInstance(), "MY_FRAG_TAG")
// .addToBackStack("MY_FRAG_TAG")
// .commit();
// This is really an override. Should call popBackStack itself.
void onPopBackStack();
}
Here's how to implement it.
public class MyFragment extends Fragment implements BackPressedFragment
#Override
public void onPopBackStack() {
/* Your code goes here, do anything you want. */
getActivity().getSupportFragmentManager().popBackStack();
}
And in your Activity, when you handle the pop (likely in both onBackPressed and onOptionsItemSelected), pop the backstack using this method:
public void popBackStack() {
FragmentManager fm = getSupportFragmentManager();
// Call current fragment's onPopBackStack if it has one.
String fragmentTag = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName();
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (currentFragment instanceof BackPressedFragment)
((BackPressedFragment)currentFragment).onPopBackStack();
else
fm.popBackStack();
}
I'm working with SlidingMenu and Fragment, present my case here and hope helps somebody.
Logic when [Back] key pressed :
When SlidingMenu shows, close it, no more things to do.
Or when 2nd(or more) Fragment showing, slide back to previous Fragment, and no more things to do.
SlidingMenu not shows, current Fragment is #0, do the original [Back] key does.
public class Main extends SherlockFragmentActivity
{
private SlidingMenu menu=null;
Constants.VP=new ViewPager(this);
//Some stuff...
#Override
public void onBackPressed()
{
if(menu.isMenuShowing())
{
menu.showContent(true); //Close SlidingMenu when menu showing
return;
}
else
{
int page=Constants.VP.getCurrentItem();
if(page>0)
{
Constants.VP.setCurrentItem(page-1, true); //Show previous fragment until Fragment#0
return;
}
else
{super.onBackPressed();} //If SlidingMenu is not showing and current Fragment is #0, do the original [Back] key does. In my case is exit from APP
}
}
}
This is a very good and reliable solution: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/
The guy has made an abstract fragment that handles the backPress behaviour and is switching between the active fragments using the strategy pattern.
For some of you there maybe a little drawback in the abstract class...
Shortly, the solution from the link goes like this:
// Abstract Fragment handling the back presses
public abstract class BackHandledFragment extends Fragment {
protected BackHandlerInterface backHandlerInterface;
public abstract String getTagText();
public abstract boolean onBackPressed();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!(getActivity() instanceof BackHandlerInterface)) {
throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
} else {
backHandlerInterface = (BackHandlerInterface) getActivity();
}
}
#Override
public void onStart() {
super.onStart();
// Mark this fragment as the selected Fragment.
backHandlerInterface.setSelectedFragment(this);
}
public interface BackHandlerInterface {
public void setSelectedFragment(BackHandledFragment backHandledFragment);
}
}
And usage in the activity:
// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment
public class TheActivity extends FragmentActivity implements BackHandlerInterface {
private BackHandledFragment selectedFragment;
#Override
public void onBackPressed() {
if(selectedFragment == null || !selectedFragment.onBackPressed()) {
// Selected fragment did not consume the back press event.
super.onBackPressed();
}
}
#Override
public void setSelectedFragment(BackHandledFragment selectedFragment) {
this.selectedFragment = selectedFragment;
}
}
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
rootView.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Fragment NameofFragment = new NameofFragment;
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container,NameofFragment);
transaction.commit();
return true;
}
return false;
}
});
return rootView;
Add addToBackStack() to fragment transaction and then use below code for Implementing Back Navigation for Fragments
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
}
});
if you are using FragmentActivity. then do like this
first call This inside your Fragment.
public void callParentMethod(){
getActivity().onBackPressed();
}
and then Call onBackPressed method in side your parent FragmentActivity class.
#Override
public void onBackPressed() {
//super.onBackPressed();
//create a dialog to ask yes no question whether or not the user wants to exit
...
}
You can use from getActionBar().setDisplayHomeAsUpEnabled() :
#Override
public void onBackStackChanged() {
int backStackEntryCount = getFragmentManager().getBackStackEntryCount();
if(backStackEntryCount > 0){
getActionBar().setDisplayHomeAsUpEnabled(true);
}else{
getActionBar().setDisplayHomeAsUpEnabled(false);
}
}
Add this code in your Activity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
And add this line in your Fragment before commit()
ft.addToBackStack("Any name");
in fragment class put this code for back event:
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
rootView.setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, new Book_service_provider()).commit();
return true;
}
return false;
}
} );
Checking the backstack works perfectly
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
if (getFragmentManager().getBackStackEntryCount() == 1)
{
// DO something here since there is only one fragment left
// Popping a dialog asking to quit the application
return false;
}
}
return super.onKeyDown(keyCode, event);
}
In your oncreateView() method you need to write this code and in KEYCODE_BACk condition you can write whatever the functionality you want
View v = inflater.inflate(R.layout.xyz, container, false);
//Back pressed Logic for fragment
v.setFocusableInTouchMode(true);
v.requestFocus();
v.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
getActivity().finish();
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent);
return true;
}
}
return false;
}
});