Skip to content

Instantly share code, notes, and snippets.

@Heroes84
Last active July 8, 2016 09:24
Show Gist options
  • Save Heroes84/104c7e03cee3e8761ebc6c216dff73af to your computer and use it in GitHub Desktop.
Save Heroes84/104c7e03cee3e8761ebc6c216dff73af to your computer and use it in GitHub Desktop.
Fragment backstack manager to access fragment all time in stack
package com.chimeraprime.prizecam.tools.fragment;
import android.os.Bundle;
import android.support.v4.BuildConfig;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import java.util.HashSet;
import java.util.Stack;
public class FragmentsManager {
private final static String FRAGMENT_TAG = "it_s_just_a_fragment_tag";
private final static String STATE_ARRAY = "backstack_array";
private final static String STATE_ARGS_ARRAY = "args_array";
private final static String STATE_SAVED_ARRAY = "saved_array";
private static final String LOG = FragmentsManager.class.getSimpleName();
/**
* If this type of fragment is already started, should it be possible to
* start the same type
*/
public static Integer FLAG_ALLOW_SAME_FRAGMENT = 1;
/**
* When fragment is in backstack go back to it, instead creating new
* fragment
*/
public static Integer FLAG_BACKSTACK_CLEAR_TOP = 2;
public static Integer FLAG_HIDE_BACK_ARROW = 3;
private Stack<Fragment> mBackStack;
private Fragment mCurrentFragment;
private boolean mAnimationsEnabled = true;
private int animationEnter = android.R.anim.fade_in;
private int animationExit = android.R.anim.fade_out;
private int animationPopEnter = android.R.anim.fade_in;
private int animationPopExit = android.R.anim.fade_out;
private int fragmentFrameId;
private FragmentChangedListener mFragmentChangedListener;
private FragmentActivity activity;
/**
* Has to be called from Activity onCreate
*/
public void onCreate(FragmentActivity a, Bundle state, int fragmentFrameId) {
this.fragmentFrameId = fragmentFrameId;
this.activity = a;
mBackStack = new Stack<Fragment>();
if (state != null) {
if (state.containsKey(STATE_ARRAY)) {
String[] fragmentsArray = state.getStringArray(STATE_ARRAY);
if (BuildConfig.DEBUG) {
StringBuilder sb = new StringBuilder();
for (String name : fragmentsArray) {
sb.append(name);
sb.append(" ");
}
Log.d(LOG, "Restoring " + sb.toString());
}
Bundle[] args = getBundleArray(state, STATE_ARGS_ARRAY);
Bundle[] states = getBundleArray(state, STATE_SAVED_ARRAY);
mAnimationsEnabled = false;
for (int i = 0; i < fragmentsArray.length; i++) {
nextFragment(fragmentsArray[i], args[i], true, null);
if (mCurrentFragment instanceof TabFragment) {
((TabFragment) mCurrentFragment).stateInfo(states[i]);
}
}
mAnimationsEnabled = true;
}
}
}
public void onDestroy() {
mFragmentChangedListener = null;
activity = null;
}
public void setFragmentChangedListener(FragmentChangedListener l) {
mFragmentChangedListener = l;
}
/**
* Has to be called from activity using it
*
* @return true if handled the request and it shouldn't be handled anywhere
* else
*/
public boolean onBackPressed() {
// first check if fragment wants to handle this back action
if (mCurrentFragment != null && (mCurrentFragment instanceof TabFragment)) {
if (((TabFragment) mCurrentFragment).onBackPressed()) {
return true;
}
if (((TabFragment) mCurrentFragment).onExit()) {
return true;
}
}
// if backstack empty just return unhandled event
if (mBackStack.empty()) {
return false;
}
// pop item from backstack and show
Fragment b = mBackStack.pop();
showFragmentFromBackStack(b);
return true;
}
private void showFragmentFromBackStack(Fragment b) {
FragmentManager fm = activity.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (mAnimationsEnabled)
ft.setCustomAnimations(animationPopEnter, animationPopExit);
if (mCurrentFragment != null) {
ft.remove(mCurrentFragment);
}
ft.attach(b);
ft.commitAllowingStateLoss();
Fragment old = mCurrentFragment;
mCurrentFragment = b;
if (mBackStack.empty()) {
showBackButton(mCurrentFragment, false);
} else {
showBackButton(mCurrentFragment, true);
}
fragmentChanged(old, mCurrentFragment);
}
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
public Fragment getLastFragment() {
if (mBackStack == null || mBackStack.size() == 0) {
return null;
} else return mBackStack.peek();
}
public boolean hasAnyHistory() {
if (mBackStack == null || mBackStack.size() == 0) {
return false;
}
return true;
}
public void nextFragment(Class<? extends Fragment> newFragClass) {
nextFragment(newFragClass.getName());
}
public void nextFragment(Class<? extends Fragment> newFragClass, Bundle args, boolean backStack) {
nextFragment(newFragClass, args, backStack, null);
}
public void nextFragment(Class<? extends Fragment> newFragClass, Bundle args, boolean backStack,
HashSet<Integer> flags) {
nextFragment(newFragClass.getName(), args, backStack, flags);
}
public void nextFragment(String newFragClassName) {
nextFragment(newFragClassName, null, false, null);
}
public void nextFragment(String newFragClassName, Bundle args, boolean backStack, HashSet<Integer> flags) {
NextFragmentParams p = new NextFragmentParams();
p.activity = activity;
p.backStack = backStack;
p.className = newFragClassName;
p.fragment = null;
p.initArgs = args;
if (flags == null) {
flags = new HashSet<Integer>();
}
nextFragment(p, flags);
}
public void nextFragment(Fragment fragment) {
nextFragment(fragment, null, false, null);
}
public void nextFragment(Fragment fragment, Bundle args, boolean backStack, HashSet<Integer> flags) {
NextFragmentParams p = new NextFragmentParams();
p.activity = activity;
p.backStack = backStack;
p.className = fragment.getClass().getName();
p.fragment = fragment;
p.initArgs = args;
if (flags == null) {
flags = new HashSet<Integer>();
}
nextFragment(p, flags);
}
private void nextFragment(NextFragmentParams params, HashSet<Integer> flags) {
// check allowSameFragment flag
if (mCurrentFragment != null && !flags.contains(FLAG_ALLOW_SAME_FRAGMENT)
&& mCurrentFragment.getClass().getName().equals(params.className)) {
return;
}
// call onExit in current fragment
if (mCurrentFragment != null && mCurrentFragment instanceof TabFragment && ((TabFragment) mCurrentFragment).onExit()) {
return;
}
// check backstackClearTop flag
boolean getFromBackstack = false;
if (flags.contains(FLAG_BACKSTACK_CLEAR_TOP)) {
for (Fragment f : mBackStack) {
if (f.getClass().getName().equals(params.className)) {
getFromBackstack = true;
break;
}
}
}
// if backstackClearTop is true and fragment is in backstack clear
// backstack to this fragment
if (getFromBackstack) {
Fragment f;
do {
f = mBackStack.pop();
} while (!f.getClass().getName().equals(params.className));
}
FragmentManager fm = params.activity.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (mAnimationsEnabled)
ft.setCustomAnimations(animationEnter, animationExit);
if (mCurrentFragment != null) {
if (params.backStack) {
mBackStack.add(mCurrentFragment);
ft.detach(mCurrentFragment);
} else {
ft.remove(mCurrentFragment);
}
}
Fragment old = mCurrentFragment;
if (params.fragment == null) {
mCurrentFragment = Fragment.instantiate(params.activity, params.className, params.initArgs);
} else {
mCurrentFragment = params.fragment;
}
ft.add(fragmentFrameId, mCurrentFragment, FRAGMENT_TAG);
showBackButton(mCurrentFragment, !mBackStack.isEmpty() && !flags.contains(FLAG_HIDE_BACK_ARROW));
ft.commitAllowingStateLoss();
fragmentChanged(old, mCurrentFragment);
}
public void clearBackStack() {
if (mBackStack != null) {
mBackStack.clear();
}
}
public void setCustomAnimationsForFragments(int enter, int exit, int popEnter, int popExit) {
animationEnter = enter;
animationExit = exit;
animationPopEnter = popEnter;
animationPopExit = popExit;
}
public int[] getCustomAnimationsForFragments() {
return new int[]{
animationEnter, animationExit, animationPopEnter, animationPopExit
};
}
public void setCustomAnimationsForFragments(int[] anims) {
setCustomAnimationsForFragments(anims[0], anims[1], anims[2], anims[3]);
}
public void showAnimations(boolean show) {
mAnimationsEnabled = show;
}
/**
* has to be called from Activity onSaveInstanceState
*/
public void onSaveInstanceState(Bundle outState) {
if (mCurrentFragment == null)
return;
String[] fragmentsStack;
Bundle[] argStack;
Bundle[] savedStack;
if (mBackStack == null) {
fragmentsStack = new String[1];
argStack = new Bundle[1];
savedStack = new Bundle[1];
} else {
fragmentsStack = new String[mBackStack.size() + 1];
argStack = new Bundle[mBackStack.size() + 1];
savedStack = new Bundle[mBackStack.size() + 1];
for (int i = 0; i < mBackStack.size(); i++) {
Fragment fragment = mBackStack.get(i);
fragmentsStack[i] = fragment.getClass().getName();
argStack[i] = fragment.getArguments();
savedStack[i] = new Bundle();
fragment.onSaveInstanceState(savedStack[i]);
}
}
fragmentsStack[fragmentsStack.length - 1] = mCurrentFragment.getClass().getName();
argStack[fragmentsStack.length - 1] = mCurrentFragment.getArguments();
savedStack[fragmentsStack.length - 1] = new Bundle();
mCurrentFragment.onSaveInstanceState(savedStack[fragmentsStack.length - 1]);
outState.putStringArray(STATE_ARRAY, fragmentsStack);
writeBundleArray(outState, STATE_ARGS_ARRAY, argStack);
writeBundleArray(outState, STATE_SAVED_ARRAY, savedStack);
}
private void writeBundleArray(Bundle b, String key, Bundle[] array) {
b.putInt(key + "length", array.length);
for (int i = 0; i < array.length; i++) {
b.putBundle(key + i, array[i]);
}
}
private Bundle[] getBundleArray(Bundle b, String key) {
int len = b.getInt(key + "length");
Bundle[] array = new Bundle[len];
for (int i = 0; i < array.length; i++) {
array[i] = b.getBundle(key + i);
}
return array;
}
private void fragmentChanged(Fragment oldFragment, Fragment newFragment) {
if (mFragmentChangedListener != null)
mFragmentChangedListener.fragmentChanged(oldFragment, newFragment);
}
private void showBackButton(Fragment current, boolean show) {
if (mFragmentChangedListener != null)
mFragmentChangedListener.showBackButton(current, show);
}
public void nextFragment(Class<? extends Fragment> newFragClass, boolean backStack) {
nextFragment(newFragClass, null, backStack);
}
public interface FragmentChangedListener {
public void fragmentChanged(Fragment oldFragment, Fragment newFragment);
public void showBackButton(Fragment current, boolean show);
}
private static class NextFragmentParams {
FragmentActivity activity;
Fragment fragment;
String className;
boolean backStack;
Bundle initArgs;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment