Last active
July 9, 2017 08:11
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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