Yamila
Yamila

Reputation: 443

Fragments stack Android

Imagine one activity with 3 fragments: starts showing the first one, select a menu option and go to the second one, select another option and go to the 3rd fragment and select again the first option an return to the second one.

f1 -> f2 -> f3 -> f2

When I press back I want the app returns to fragment 3 and when I press back again it should return to fragment 1 and if press back again, close the app. Something like if the fragment exists, move it to top of the stack and if not, create it.

Thank you!

Upvotes: 0

Views: 61

Answers (2)

Vilen
Vilen

Reputation: 5061

Here is solution I came up over time. The idea is following, you need to keep a stack data structure and whenever you add a fragment add it to stack as well, then override onBackPress method and check if stack is not empty then replace your fragment container with new fragment from top of the stack when it is empty do super.onbackpress So here is a parent class for all kind of fragment based navigation.

public abstract class FragmentsStackActivity extends BaseActivity {
    public static final String TAG_BUNDLE = "bundle_tag";

    protected final Bundle fragmentArgs = new Bundle();
    protected Stack<Fragment> fragments = new Stack<>();

    abstract protected void setupFragments();

    public void setFragmentArguments(Fragment fragment, Bundle arguments){
        if(!fragments.isEmpty() && fragments.peek()!=fragment){
            fragment.setArguments(arguments);
        }
    }
    public void setFragmentFromStack() {
        if(!fragments.isEmpty()) {
            Fragment fragment = fragments.peek();
            final Fragment oldFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
            if (oldFragment == null || oldFragment != fragment) {
                getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                //transaction.setCustomAnimations(R.anim.animator_left_right_in, R.anim.animator_left_right_in);
                transaction.replace(R.id.fragment_container, fragment).commit();
            }
        }else {
            finish();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        //TODO need to save fragment stack
    }
}

example of an activity that extends this class

public class LoginActivity extends FragmentsStackActivity{

    private final MyFragment1 fragment1 = new MyFragment1();
    private final MyFragment2 fragment2 = new MyFragment2();

    private final User mUser = new User();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        setupFragments();
        setFragmentFromStack();
    }


    @Override
    protected void setupFragments() {
        fragments.add(fragment2);
        //fragment2.setNotifier(this); // I use notifiers listener but you can choose whatever convenient for you
        Bundle fragmentArgs = new Bundle();
        fragmentArgs.putBoolean(Constants.TAG_LOGIN, true);
        fragmentArgs.putParcelable(User.TAG, mUser);
        fragmentArgs.putInt(Constants.TYPE, getIntent().getIntExtra(Constants.TYPE, 0));
        fragment2.setArguments(fragmentArgs);
        //fragment1.setNotifier(this); // I use notifiers listener but you can choose whatever convenient for you
    }


    // this method teals with handling messages from fragments in order to provide navigation 
    // when some actions taken inside the fragment, you can implement your own version 
    public void onReceiveMessage(String tag, Bundle bundle) {
        switch (tag) {
            case MyFragment2.TAG_BACK:
            case MyFragment1.TAG_BACK:
                fragments.pop();
                setFragmentFromStack();
                break;
            case MyFragment2.TAG_NEXT:
                fragment1.setArguments(bundle);
                fragments.add(fragment1);
                setFragmentFromStack();
                break;
            case MyFragment1.TAG_NEXT:
                goToWelcomeScreen(bundle);
                finish();
                break;
        }
    }

    private void goToWelcomeScreen(Bundle bundle){

    }
}

Upvotes: 1

johnrao07
johnrao07

Reputation: 6938

You can implement this with the help of the following code:

// transaction.replace(R.id.detailFragment, frag1);
Transaction.remove(null).add(frag1)  // frag1 on view

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag1).add(frag2).addToBackStack(null)  // frag2 on view

// transaction.replace(R.id.detailFragment, frag3);
Transaction.remove(frag2).add(frag3)  // frag3 on view

And for better understanding, have a ook at the following snippet:

// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
                       .add(detailFragment, "detail")
                       // Add this transaction to the back stack
                       .addToBackStack()
                       .commit();



getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() {
        public void onBackStackChanged() {
            // Update your UI here.
        }
    });

have a look here http://developer.android.com/training/implementing-navigation/temporal.html

Upvotes: 0

Related Questions