Search code examples
androidandroid-fragmentsandroid-listfragment

How to pass selected item from ListFragment to previous Fragment after calling popBackStack()?


I have prepared a very simple test case with 1 activity and 2 fragments for my question:

screenshot

Initially MainActivity displays MyMainFragment.

When user touches "Select item..." button, MainActivity displays MyListFragment with:

public void selectedButtonClicked() {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    int index = prefs.getInt(INDEX, -1);
    Fragment fragment = MyListFragment.newInstance(index);
    getFragmentManager().beginTransaction()
        .addToBackStack(null)
        .replace(R.id.root, fragment, LIST)
        .commit();
}

After user touches one of the items in the list, MainActivity stores the selected item position in shared preferences and calls popBackStack() to display the MyMainFragment again:

public void itemSelected(int index) {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    Editor editor = prefs.edit();
    editor.putInt(INDEX, index);
    editor.commit();
    getFragmentManager().popBackStack();
    // How to show the index in mSelectedTextView?
}

I.e. the MainActivity in my app does all the "heavy work": it displays 1 of 2 fragments and keeps the user data in shared preferences.

My question is: how to display the selected item (the "Item 07" in the above screenshot) in the mSelectedTextView of the MyMainFragment?

I'm looking for a way to do it properly, without any hacks (for example fragments shouldn't touch shared preferences).

UPDATE: I've tried the suggestion by corsair992 (thanks!)

public void itemSelected(int index) {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    Editor editor = prefs.edit();
    editor.putInt(INDEX, index);
    editor.commit();
    getFragmentManager().popBackStackImmediate();
    MyMainFragment f = (MyMainFragment) getFragmentManager().findFragmentById(R.id.root);
    // call a method in MyMainFragment to update mSelectedTextView
    f.setText("Selected index: " + index);
}

but it only works, when user touches an item in MyListFragment. It does not however work, when user returns to MyMainFragment by touching Back button.


Solution

  • As I see it, you already have a reasonable first part to the answer (suggestion by corsair992 - pass the value from the item selected) the second part is how do you handle the back key.

    There are a few ways of doing that (listening to the back stack etc.) but the one I have used most fequently is:

    declare a back key listener interface:

    public interface BackKeyListener {
       boolean onBackPressed();
    }
    

    in your main activity add the following:

    import BackKeyListener;
    void onBackKeyPressed() {
       boolean backKeyHandled = false;
       Fragment activeFragment = getActiveFragment();
       if (activeFragment instanceof BackKeyListener) {
          backKeyHandled = ((BackKeyListener) activeFragment).onBackKeyPressed();
       }
       if (!handled) {
          // If should process back key normally, pass to super..
          super.onBackKeyPressed();
       }
    }
    
    Fragment getActiveFragment() {
       // I'm assuming you place all your fragments here, if not..
       // alter to suit
       return getFragmentManager().findFragmentById(R.id.root);
    }
    

    in MyListFragment add the following:

    import BackKeyListener;
    
    class MyListFragment extends Fragment(orsomething) implements BackKeyListener
    
    public boolean onBackPressed() {
      // User pressed back, select default item..
      ((MainActivity) getActivity()).itemSelected(selectedItem);
    
      // In this case, prevent normal back processing or
      // you might get a double backstack pop.
      return true;
    }
    

    Using an interface on the fragment allows you to "not care" what the active fragment is. If it implements the BackKeyListener, the MainActivity will call it when the back key is pressed. This gives you the option of passing a value back to the activity.