Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh ActionBar navigation item during traversing the Fragment back stack?

The Android 4.1 ActionBar provides a useful navigation mode as a list or tab. I am using a SpinnerAdapter to select from three fragments to be displayed in view android.R.id.content. The onNavigationItemSelected() listener then inflates each fragment to the view and adds it to the back stack using FragmentTransaction.addToBackStack(null).

This all works as advertised, but I don't know how to update the ActionBar to reflect the current back stack. Using the ActionBar.setSelectedNavigationItem(position) works but also triggers a new OnNavigationListener() which also creates another FragmentTransaction (not the effect I want). The code is shown below for clarification. Any help with a solution is appreciated.


public class CalcActivity extends Activity {
private String[] mTag = {"calc", "timer", "usage"};
private ActionBar actionBar;

/** An array of strings to populate dropdown list */
String[] actions = new String[] {
    "Calculator",
    "Timer",
    "Usage"
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.actionBar = getActionBar();

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    // may not have room for Title in actionbar
    actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

    actionBar.setListNavigationCallbacks(
    // Specify a SpinnerAdapter to populate the dropdown list.
    new ArrayAdapter<String>(
        actionBar.getThemedContext(),
        android.R.layout.simple_list_item_1,
        android.R.id.text1,
        actions),
    // Provide a listener to be called when an item is selected.
    new NavigationListener()
    );      
}

public class NavigationListener implements ActionBar.OnNavigationListener {
    private Fragment mFragment;
    private int firstTime = 0;

    public boolean onNavigationItemSelected(int itemPos, long itemId) {
        mFragment = getFragmentManager().findFragmentByTag(mTag[itemPos]);

        if (mFragment == null) {
            switch (itemPos) {
            case 0:
                mFragment = new CalcFragment();
                break;
            case 1:
                mFragment = new TimerFragment();
                break;
            case 2:
                mFragment = new UsageFragment();
                break;
            default:
                return false;
            }               
            mFragment.setRetainInstance(true);
        }

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        if (firstTime == 0) {
            firstTime++;
            ft.add(android.R.id.content, mFragment, mTag[itemPos]);
        } else {
            ft.replace(android.R.id.content, mFragment, mTag[itemPos]);
            ft.addToBackStack(null);
        }
        ft.commit();

        Toast.makeText(getBaseContext(), "You selected : " + 
                actions[itemPos], Toast.LENGTH_SHORT).show();

        return true;
    }       
}

public static class CalcFragment extends Fragment {             
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_calc, container, false);
    return v;
    }   
}

public static class TimerFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_timer, container, false);
    return v;
    }   
}

public static class UsageFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_usage, container, false);
    return v;
    }
}
like image 499
GregM Avatar asked Oct 17 '12 20:10

GregM


1 Answers

You could do something like this:

  1. Create a boolean to track when you are selecting a navigation item based on the back button:

    private boolean mListIsNavigatingBack = false;
    
  2. Override onBackPressed, in the override, check if the backstack has items, if so handle yourself, if not call the superclass:

    public void onBackPressed() {
        if(getFragmentManager().getBackStackEntryCount() > 0){
            mListIsNavigatingBack = true;
    
            //You need to get the previous index in the backstack through some means
            //possibly by storing it in a stack
            int previousNavigationItem = ???;
    
            getActionBar().setSelectedNavigationItem(previousNavigationItem);
        }
        else{
            super.onBackPressed();
        }
    }
    
  3. Inside NavigationListener, handle the mListIsNavigatingBack state, manually pop the back stack and unset the state:

    if(mListIsNavigatingBack){
        if(fm.getBackStackEntryCount() > 0){
            fm.popBackStack();
        }
        mListIsNavigatingBack = false;
    }
    
like image 188
Error 454 Avatar answered Oct 27 '22 00:10

Error 454