Skip to content

Instantly share code, notes, and snippets.

@oing9179
Last active July 9, 2017 08:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oing9179/f52d5b684b295911b4149a2157b6adb1 to your computer and use it in GitHub Desktop.
Save oing9179/f52d5b684b295911b4149a2157b6adb1 to your computer and use it in GitHub Desktop.
Utility class help you to drop Fragment state before it's being restored.
package your.packagename;
import android.app.Activity;
import android.os.Bundle;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
/**
* Prevent Fragment being restored in {@link Activity#onCreate(Bundle)}.
*
* @see <a href="https://stackoverflow.com/questions/15519214/prevent-fragment-recovery-in-android">https://stackoverflow.com/questions/15519214/prevent-fragment-recovery-in-android</a>
*/
public class FragmentStateUtil {
private final String FRAGMENTS_TAG;
private final Bundle mBundleSavedInstanceState;
private final FragmentManagerState mFragmentManagerState;
/**
* <span style="font-weight: bold;">NOTE:</span> Do it <span style="font-weight: bold;">BEFORE</span>
* {@linkplain android.app.Activity#onCreate(Bundle) super.onCreate(Bundle)}
*
* @param activity
* @param savedInstanceState
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public FragmentStateUtil(Activity activity, Bundle savedInstanceState) throws NoSuchFieldException, IllegalAccessException {
this.FRAGMENTS_TAG = getFragmentsTagString(activity);
if (FRAGMENTS_TAG == null) {
throw new IllegalStateException("Can't find FRAGMENTS_TAG in class " + activity.getClass().getName());
}
this.mBundleSavedInstanceState = savedInstanceState;
this.mFragmentManagerState = new FragmentManagerState(savedInstanceState.getParcelable(FRAGMENTS_TAG));
}
/**
* Find value of field {@code FRAGMENTS_TAG} from Activity, this field exists in these classes:<br/>
* <ol>
* <li>{@link android.app.Activity#FRAGMENTS_TAG}</li>
* <li>{@link android.support.v4.app.FragmentActivity#FRAGMENTS_TAG}</li>
* </ol>
* You may not need this, but just in case.
*
* @param activity
* @return Value of {@code FRAGMENTS_TAG}, {@code null} if not found.
* @throws IllegalAccessException
*/
public static String getFragmentsTagString(Activity activity) throws IllegalAccessException {
Field lFieldStrFragmentsTag = null;
for (Class lClass = activity.getClass(); !lClass.equals(Object.class); ) {
try {
lFieldStrFragmentsTag = lClass.getDeclaredField("FRAGMENTS_TAG");
break;
} catch (NoSuchFieldException ignore) {
}
lClass = lClass.getSuperclass();
}
if (lFieldStrFragmentsTag == null) return null;
lFieldStrFragmentsTag.setAccessible(true);
return (String) lFieldStrFragmentsTag.get(activity);
}
/**
* Drop all fragment's state.
*/
public void dropFragmentState() {
mBundleSavedInstanceState.remove(FRAGMENTS_TAG);
}
/**
* Drop fragment state by fragment ID.
*
* @param fragmentId
* @return Dropped or not.
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @see android.app.FragmentTransaction#add(int, android.app.Fragment)
* @see android.app.FragmentTransaction#add(int, android.app.Fragment, String)
*/
public boolean dropFragmentState(int fragmentId) throws NoSuchFieldException, IllegalAccessException {
return mFragmentManagerState.dropFragmentState(fragmentId);
}
/**
* Drop fragment state by fragment tag.
*
* @param tag
* @return Dropped or not.
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @see android.app.FragmentTransaction#add(android.app.Fragment, String)
* @see android.app.FragmentTransaction#add(int, android.app.Fragment, String)
*/
public boolean dropFragmentState(String tag) throws NoSuchFieldException, IllegalAccessException {
return mFragmentManagerState.dropFragmentState(tag);
}
/**
* Drop fragment state by class name.
*
* @param klass
* @return How many fragment state dropped, {@code 0} is possible.
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public int dropFragmentState(Class klass) throws NoSuchFieldException, IllegalAccessException {
return mFragmentManagerState.dropFragmentState(klass);
}
}
/**
* @see android.app.FragmentManager.FragmentManagerState
*/
final class FragmentManagerState {
private final Class CLASS_FragmentManagerState;
private final Field FIELD_mActive;
private final Field FIELD_mAdded;
private final Object mInstance;
public FragmentManagerState(Object fragmentManagerState) throws NoSuchFieldException {
if (fragmentManagerState == null) throw new NullPointerException("fragmentManagerState");
mInstance = fragmentManagerState;
CLASS_FragmentManagerState = mInstance.getClass();
FIELD_mActive = CLASS_FragmentManagerState.getDeclaredField("mActive");
FIELD_mActive.setAccessible(true);
FIELD_mAdded = CLASS_FragmentManagerState.getDeclaredField("mAdded");
FIELD_mAdded.setAccessible(true);
}
public FragmentState[] getActive() throws IllegalAccessException, NoSuchFieldException {
Object lObjectArrFragmentState = FIELD_mActive.get(mInstance);
FragmentState[] lFragmentStateArray = new FragmentState[Array.getLength(lObjectArrFragmentState)];
for (int i = 0; i < lFragmentStateArray.length; i++) {
lFragmentStateArray[i] = new FragmentState(Array.get(lObjectArrFragmentState, i));
}
return lFragmentStateArray;
}
public void setActive(FragmentState[] fragmentStates) throws IllegalAccessException {
if (fragmentStates == null || fragmentStates.length < 1) {
return;
}
Object lObjectArrFragmentState = Array.newInstance(fragmentStates[0].getRealClass(), fragmentStates.length);
for (int i = 0; i < fragmentStates.length; i++) {
Array.set(lObjectArrFragmentState, i, fragmentStates[i].getRealInstance());
}
FIELD_mActive.set(mInstance, lObjectArrFragmentState);
}
public int[] getAdded() throws IllegalAccessException {
return (int[]) FIELD_mAdded.get(mInstance);
}
public void setAdded(int[] added) throws IllegalAccessException {
FIELD_mAdded.set(mInstance, added);
}
public boolean dropFragmentState(final int fragmentId) throws NoSuchFieldException, IllegalAccessException {
FragmentState[] lArrFragmentState = getActive();
for (int i = 0, lnLength = lArrFragmentState.length; i < lnLength; i++) {
FragmentState lFragmentState = lArrFragmentState[i];
if (lFragmentState.getFragmentId() == fragmentId) {
dropFragmentStateByIndex(i);
return true;
}
}
return false;
}
public boolean dropFragmentState(final String tag) throws NoSuchFieldException, IllegalAccessException {
FragmentState[] lArrFragmentState = getActive();
for (int i = 0, lnLength = lArrFragmentState.length; i < lnLength; i++) {
FragmentState lFragmentState = lArrFragmentState[i];
if (lFragmentState.getTag().equals(tag)) {
dropFragmentStateByIndex(i);
return true;
}
}
return false;
}
public int dropFragmentState(final Class klass) throws NoSuchFieldException, IllegalAccessException {
FragmentState[] lArrFragmentState = getActive();
int lnFragmentStateDropped = 0;
for (int i = 0, lnLength = lArrFragmentState.length; i < lnLength; i++) {
FragmentState lFragmentState = lArrFragmentState[i];
if (lFragmentState.getClassName().equals(klass.getName())) {
dropFragmentStateByIndex(i);
lnFragmentStateDropped++;
lArrFragmentState = getActive();
lnLength = lArrFragmentState.length;
i--;
}
}
return lnFragmentStateDropped;
}
private void dropFragmentStateByIndex(int index) throws NoSuchFieldException, IllegalAccessException {
FragmentState[] lArrFragmentState = getActive();
int[] lnArrAdded = getAdded();
FragmentState[] lArrFragmentStateNew = new FragmentState[lArrFragmentState.length - 1];
int[] lnArrAddedNew = new int[lnArrAdded.length - 1];
for (int i = 0, iNew = 0; i < lArrFragmentState.length; i++) {
if (i == index) continue;
lArrFragmentStateNew[iNew] = lArrFragmentState[i];
lnArrAddedNew[iNew] = lnArrAdded[i];
iNew++;
}
setActive(lArrFragmentStateNew);
setAdded(lnArrAddedNew);
}
}
/**
* @see android.app.Fragment.FragmentState
*/
final class FragmentState {
private final Class CLASS_FragmentState;
private final Field FIELD_mFragmentId;
private final Field FIELD_mTag;
private final Field FIELD_mClassName;
private final Object mInstance;
public FragmentState(Object fragmentState) throws NoSuchFieldException {
if (fragmentState == null) throw new NullPointerException("fragmentState");
mInstance = fragmentState;
CLASS_FragmentState = mInstance.getClass();
FIELD_mFragmentId = CLASS_FragmentState.getDeclaredField("mFragmentId");
FIELD_mFragmentId.setAccessible(true);
FIELD_mTag = CLASS_FragmentState.getDeclaredField("mTag");
FIELD_mTag.setAccessible(true);
FIELD_mClassName = CLASS_FragmentState.getDeclaredField("mClassName");
FIELD_mClassName.setAccessible(true);
}
public Class getRealClass() {
return CLASS_FragmentState;
}
public Object getRealInstance() {
return mInstance;
}
public int getFragmentId() throws IllegalAccessException {
return FIELD_mFragmentId.getInt(mInstance);
}
public String getTag() throws IllegalAccessException {
return (String) FIELD_mTag.get(mInstance);
}
public String getClassName() throws IllegalAccessException {
return (String) FIELD_mClassName.get(mInstance);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment