26

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?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
DJ-DOO
  • 4,545
  • 15
  • 58
  • 98

9 Answers9

35

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();
           }
        }
    }
}
Shubham Chaudhary
  • 47,722
  • 9
  • 78
  • 80
Ioane Sharvadze
  • 2,118
  • 21
  • 35
  • 1
    Other solutions also work, but for me this looks better. :) – Ioane Sharvadze May 23 '16 at 09:08
  • What if my fragment has some child fragments where I'd also like to handle OnBackPressed? – Micer Aug 20 '17 at 07:09
  • 1
    @Micer In that case, you can listen to `onBackPressed()` method call in fragment and there you can call `getChildFragmentManager()` and do traverse child fragments and call `onBackPressed()` if needed :) BTW the best case would be to put this logic into `BaseFragment` and `BaseActivity` – Ioane Sharvadze Aug 20 '17 at 15:29
24

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();
        }
    });
}
tiguchi
  • 5,392
  • 1
  • 33
  • 39
  • thanks for the reply, the reason I'm trying to avoid the back stack is when I added to the back stack and removed the fragment, when I click on the button to open that fragment again I was getting a black screen, should I be doing some sort of retrieval in that case? I'm new to fragments and I'm trying to take over previously written code. – DJ-DOO Aug 12 '13 at 14:58
  • @DJ-DOO I already thought so, that this is the problem. When I started with fragments I ran into the exact same issue. However, there is a workaround for that problem. Let me dig up some code and update my answer... – tiguchi Aug 12 '13 at 15:00
  • that's great..I'm stuck at the moment and am unsure what to do next – DJ-DOO Aug 12 '13 at 15:06
  • I'm just testing this at the moment, although I'm not sure if it will solve that particular problem. The problem is have if I have for example fragment A, B, C. I go from A -> B -> C, I click back A <- B <- C , but If I click the menu to go to C again, that's when I get the black screen – DJ-DOO Aug 12 '13 at 15:14
  • @DJ-DOO I remember faintly that these fragment transactions are sometimes pretty weird. How exactly do you switch from fragment to fragment? Could you update your question and give a code example? – tiguchi Aug 12 '13 at 15:20
  • Thanks for your help, I am now getting a crash and a null pointer exception, 08-12 16:18:31.145: E/AndroidRuntime(7555): at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:656) 08-12 16:18:31.145: E/AndroidRuntime(7555): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460) ===== PLEASE SEE MY QUESTION UPDATE – DJ-DOO Aug 12 '13 at 15:21
  • i have been banned from posting questions, I'm not sure why this question was down voted, I thought it was clear as to what i was asking as did another contributor...apologies if it's not clear enough, I'm not sure what way to structure the question. – DJ-DOO Aug 12 '13 at 15:45
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35295/discussion-between-nobu-games-and-dj-doo) – tiguchi Aug 12 '13 at 15:45
4
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                Log.w("a","")
            }
        })
DavidUps
  • 366
  • 3
  • 9
3

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;
    }
};
  • 5
    where did you define 'pressed' variable? – Daryn Dec 09 '13 at 07:15
  • 1
    You can define 'pressed' like this: OnKeyListener pressed = new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if( keyCode == KeyEvent.KEYCODE_BACK ){ return true; } return false; } }; – icastell Jan 07 '14 at 07:56
  • 2
    @user2886881 Override `onKey()` in a Fragment? I don't think so. – IgorGanapolsky Oct 16 '15 at 14:13
3

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;
        }
    });}
Steven.Nguyen
  • 1,034
  • 13
  • 14
2

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);
    }
negersiu
  • 552
  • 3
  • 20
  • This solution really works well but i am thinking, is this hack or solution for handling on backpressed – androidXP Jan 22 '18 at 20:15
2

For a Fragment you can simply add

  getActivity().onBackPressed();

to your code

Chidinma
  • 19
  • 1
  • 9
2

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
            
        }
    }
Tonnie
  • 4,865
  • 3
  • 34
  • 50
-7

Use this:

@Override
public void onBackPressed() {
    int fragments = getFragmentManager().getBackStackEntryCount();
    if (fragments == 1) {
        finish();
    }
    super.onBackPressed();
}
meduvigo
  • 1,523
  • 12
  • 7