Last active
December 20, 2016 14:23
-
-
Save technoir42/91d1b9e73fbfa145bb32b713f8eef338 to your computer and use it in GitHub Desktop.
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
import android.annotation.SuppressLint; | |
import android.os.Bundle; | |
import android.os.Parcelable; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.support.v4.app.FragmentTransaction; | |
import android.support.v4.util.LongSparseArray; | |
import android.support.v4.view.PagerAdapter; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import java.util.HashSet; | |
import java.util.Set; | |
/** | |
* An implementation of {@link PagerAdapter} similar to {@link android.support.v4.app.FragmentStatePagerAdapter} | |
* which items can be changed dynamically. | |
*/ | |
public abstract class DynamicFragmentStatePagerAdapter extends PagerAdapter { | |
private static final String KEY_FRAGMENTS = "fragments"; | |
private static final String KEY_STATES = "states"; | |
private final FragmentManager fragmentManager; | |
private final LongSparseArray<Fragment> fragments = new LongSparseArray<>(); | |
private final LongSparseArray<Fragment.SavedState> savedStates = new LongSparseArray<>(); | |
private FragmentTransaction currentTransaction; | |
private Fragment currentPrimaryItem; | |
public DynamicFragmentStatePagerAdapter(FragmentManager fragmentManager) { | |
this.fragmentManager = fragmentManager; | |
} | |
public abstract Fragment getItem(int position); | |
public abstract long getItemId(int position); | |
@Nullable | |
public Fragment getItemById(long itemId) { | |
return fragments.get(itemId); | |
} | |
@Override | |
@SuppressLint("CommitTransaction") | |
public Object instantiateItem(ViewGroup container, int position) { | |
final long itemId = getItemId(position); | |
Fragment fragment = fragments.get(itemId); | |
if (fragment != null) { | |
return fragment; | |
} | |
fragment = getItem(position); | |
final Fragment.SavedState savedState = savedStates.get(itemId); | |
if (savedState != null) { | |
fragment.setInitialSavedState(savedState); | |
} | |
fragment.setMenuVisibility(false); | |
fragment.setUserVisibleHint(false); | |
fragments.put(itemId, fragment); | |
if (currentTransaction == null) { | |
currentTransaction = fragmentManager.beginTransaction(); | |
} | |
currentTransaction.add(container.getId(), fragment); | |
return fragment; | |
} | |
@Override | |
@SuppressLint("CommitTransaction") | |
public void destroyItem(ViewGroup container, int position, Object object) { | |
final Fragment fragment = (Fragment) object; | |
final int index = fragments.indexOfValue(fragment); | |
final long itemId = fragments.keyAt(index); | |
if (fragment.isAdded() && getItemPosition(fragment) != POSITION_NONE) { | |
savedStates.put(itemId, fragmentManager.saveFragmentInstanceState(fragment)); | |
} else { | |
savedStates.remove(itemId); | |
} | |
fragments.removeAt(index); | |
if (currentTransaction == null) { | |
currentTransaction = fragmentManager.beginTransaction(); | |
} | |
currentTransaction.remove(fragment); | |
} | |
@Override | |
public void setPrimaryItem(ViewGroup container, int position, Object object) { | |
final Fragment fragment = (Fragment) object; | |
if (currentPrimaryItem != fragment) { | |
if (currentPrimaryItem != null) { | |
currentPrimaryItem.setMenuVisibility(false); | |
currentPrimaryItem.setUserVisibleHint(false); | |
} | |
if (fragment != null) { | |
fragment.setMenuVisibility(true); | |
fragment.setUserVisibleHint(true); | |
} | |
currentPrimaryItem = fragment; | |
} | |
} | |
@Override | |
public void startUpdate(ViewGroup container) { | |
if (container.getId() == View.NO_ID) { | |
throw new IllegalStateException("ViewPager with adapter " + this + " requires a view id"); | |
} | |
} | |
@Override | |
public void finishUpdate(ViewGroup container) { | |
if (currentTransaction != null) { | |
currentTransaction.commitNowAllowingStateLoss(); | |
currentTransaction = null; | |
} | |
} | |
@Override | |
public boolean isViewFromObject(View view, Object object) { | |
return ((Fragment) object).getView() == view; | |
} | |
@Override | |
public int getItemPosition(Object object) { | |
final Fragment fragment = (Fragment) object; | |
final int index = fragments.indexOfValue(fragment); | |
if (index != -1) { | |
final long itemId = fragments.keyAt(index); | |
for (int position = 0, itemCount = getCount(); position < itemCount; position++) { | |
final long currentItemId = getItemId(position); | |
if (currentItemId == itemId) { | |
return position; | |
} | |
} | |
} | |
return POSITION_NONE; | |
} | |
@Override | |
public void notifyDataSetChanged() { | |
super.notifyDataSetChanged(); | |
purgeStates(); | |
} | |
@Override | |
public Parcelable saveState() { | |
final Bundle state = new Bundle(); | |
final int stateCount = savedStates.size(); | |
if (stateCount > 0) { | |
final Bundle stateBundle = new Bundle(); | |
for (int i = 0; i < stateCount; i++) { | |
stateBundle.putParcelable(String.valueOf(savedStates.keyAt(i)), savedStates.valueAt(i)); | |
} | |
state.putBundle(KEY_STATES, stateBundle); | |
} | |
final int fragmentCount = fragments.size(); | |
if (fragmentCount > 0) { | |
final Bundle fragmentBundle = new Bundle(); | |
for (int i = 0; i < fragmentCount; i++) { | |
final Fragment fragment = fragments.valueAt(i); | |
if (fragment.isAdded()) { | |
fragmentManager.putFragment(fragmentBundle, String.valueOf(fragments.keyAt(i)), fragment); | |
} | |
} | |
state.putBundle(KEY_FRAGMENTS, fragmentBundle); | |
} | |
return state; | |
} | |
@Override | |
public void restoreState(Parcelable state, ClassLoader loader) { | |
final Bundle bundle = (Bundle) state; | |
bundle.setClassLoader(loader); | |
fragments.clear(); | |
savedStates.clear(); | |
final Bundle stateBundle = bundle.getBundle(KEY_STATES); | |
if (stateBundle != null) { | |
for (String key : stateBundle.keySet()) { | |
savedStates.put(Long.parseLong(key), stateBundle.getParcelable(key)); | |
} | |
} | |
final Bundle fragmentsBundle = bundle.getBundle(KEY_FRAGMENTS); | |
if (fragmentsBundle != null) { | |
for (String key : fragmentsBundle.keySet()) { | |
final Fragment fragment = fragmentManager.getFragment(fragmentsBundle, key); | |
if (fragment != null) { | |
fragment.setMenuVisibility(false); | |
fragments.put(Long.parseLong(key), fragment); | |
} | |
} | |
} | |
} | |
private void purgeStates() { | |
final Set<Long> itemIds = new HashSet<>(); | |
for (int position = 0, itemCount = getCount(); position < itemCount; position++) { | |
final long itemId = getItemId(position); | |
itemIds.add(itemId); | |
} | |
for (int index = 0; index < savedStates.size(); ) { | |
final long itemId = savedStates.keyAt(index); | |
if (!itemIds.contains(itemId)) { | |
savedStates.removeAt(index); | |
} else { | |
index++; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment