0

I have been researching this for a few days and have yet to find a working solution. There is lots of information available but because of my inexperience with Android I can't get any of the suggestions to work.

I have an Activity with a stack of 3 Fragments on top of it all of which are presented using FragmentManager Transactions and added to the backstack. While the third Fragment is active, I need to intercept the onBackPressed() method and perform some extra stuff before the Fragment is destroyed.

I have tried using Callbacks and Interfaces to capture onBackPressed() at the Activity and send it to the 3rd Fragment with no luck.

What is the proper way to have a Fragment deep in the stack watch for the Activity's onBackPressed() method.

Let me know if this is not clear.

Thanks for the help.

Sev
  • 883
  • 1
  • 14
  • 34
  • Is onBackPressed() necessary? Or are you just trying to do something as the fragment is destroyed? – Evan Bashir Jul 03 '15 at 22:02
  • Maybe it will be better to Override `onPause` ? – Damian Kozlak Jul 03 '15 at 22:02
  • The last 2 Fragments on the stack need to be popped at the same time, or one immediately following each other and I am accomplishing this just fine with my built in cancel button by calling popBackStack() 2 times (probably not the best way to do it...) so I need to do the same onBackPressed() otherwise only 1 Fragment gets destroyed. – Sev Jul 03 '15 at 22:17
  • Did you read webpage http://developer.android.com/training/implementing-navigation/temporal.html#back-fragments ? I think at this point, you should post the relevant code for us to see any possible issues. – The Original Android Jul 04 '15 at 00:45

3 Answers3

0

Not compiled and tested, but this lays out the basic approach:

public interface BackButonListener {
    boolean OnBackButtonPressed();
} 

public interface BackButtonWatchable {
     void addBackButtonListener(BackButtonListener listener);
     void removeBackButtonListener(BackButtonListener listener);
}

public class MyActivity extends Activity implements BackButtonWatchable {
...
    private static ArrayList<BackButtonListener> backButtonListeners
        = new ArrayList<BackButtonListener>();
    @Override 
    public void addBackButtonListener(BackButtonListener listener) {
          backButtonListeners.add(listener);
    }
    @Override
    public void removeBackButtonListener(BackButtonListener listener) {
          backButtonListeners.remove(listener);
    }
...
    @Override 
    public void onBackButtonPressed() 
    {
        boolean supressBackButton = false;
        for (BackButtonListener listener: backButtonListeners)
        {
             if (!listener.OnBackButtonPressed()) {
                  suppressBackButton = true;
             }
        }
        if (!suppressBackButton) {
            super.onBackButtonPressed();
        }
    }
}


public class MyFragment extends Fragment implements BackButtonListerer {
     @Override 
     public void onResume()
     {
          ((BackButtonWatchable)getActivity()).addBackButtonListener(this);
     }
     @Override 
     public void onPause()     {
          ((BackButtonWatchable)getActivity()).removeBackButtonListener(this);
     }
}
Robin Davies
  • 7,547
  • 1
  • 35
  • 50
  • To be clear, we are dealing with an Activity and a Fragment, are both interfaces in the Activity, or is one in Activity and one in Fragment? – Sev Jul 03 '15 at 22:41
  • I was proposing that the interfaces be declared at top level. The don't belong in the activity. If you only ever want to use your fragment in one activity, you can just cast the value of Fragment.getActivity() to your top-level class, and not use an interface at all. – Robin Davies Jul 04 '15 at 04:47
  • ... Probably the correct pattern is to declare the interfaces in the fragment. In which case BackButtonWatchable should be renamed to MyFragment.MyFragmentListener. (an excellent pattern for fragments), and then any activity that contains the fragment must implement MyFragment.MyFragmentListener. Tempting to just cast MyFragment.getActivity() to your top-level class, but if you ever did want to rehost the fragment in another activity, things get difficult. The MyFragmentListener interface is helpful in that it forces you to keep the ties between the fragment and the activity lean and mean. – Robin Davies Jul 04 '15 at 04:50
0

Crete interface

public interface OnBackPressedListener {
   void onBackPressed();
}

and create field in activity

private OnBackPressedListener mListener;

and your onBackPressed() should look like

if (mListener != null) {
   mListener.onBackPressed();
} else { /* do your acitivty usual stuff */ }

When fragment is created you register this fragment as mListener in your activity and don't forger to set it to null in onDestroy.

Yaroslav
  • 4,750
  • 3
  • 22
  • 33
0

This is the post that answered my question. For a Android newbie, this told me where everything needed to go.

https://stackoverflow.com/a/30865486/2640458

The Fragment that needed to see the onBackPress() method from it's activity:

public class RatingFragment extends Fragment implements ContentActivity.OnBackPressedListener  {

@Override
public void doBack() {
    getFragmentManager().popBackStack();
}

The very important subscription to the listener in the above Fragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_rating, container, false);

    ((ContentActivity)getActivity()).setOnBackPressedListener(this);
}

The Activity that needs to send the onBackPress() method to the above Fragment:

public class ContentActivity extends Activity {

protected OnBackPressedListener onBackPressedListener;

public interface OnBackPressedListener {
    void doBack();
}

public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
    this.onBackPressedListener = onBackPressedListener;
}

@Override
public void onBackPressed() {
    if (onBackPressedListener != null)
        onBackPressedListener.doBack();
    else
        super.onBackPressed();
}

@Override
protected void onDestroy() {
    onBackPressedListener = null;
    super.onDestroy();
}
}
Community
  • 1
  • 1
Sev
  • 883
  • 1
  • 14
  • 34
  • Looks good, congratulations! Your answer is similar to the other posted answers. You can show your appreciation by upvoting the other posts for simply being helpful. – The Original Android Jul 04 '15 at 01:41