/* * Copyright 2014 Soichiro Kashima * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ksoichiro.android.observablescrollview; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.util.SparseArray; import android.view.ViewGroup; /** * FragmentStatePagerAdapter that caches each pages. * FragmentStatePagerAdapter is also originally caches pages, * but its keys are not public nor documented, so depending * on how it create cache key is dangerous. * This adapter caches pages by itself and provide getter method to the cache. */ public abstract class CacheFragmentStatePagerAdapter extends FragmentStatePagerAdapter { private static final String STATE_SUPER_STATE = "superState"; private static final String STATE_PAGES = "pages"; private static final String STATE_PAGE_INDEX_PREFIX = "pageIndex:"; private static final String STATE_PAGE_KEY_PREFIX = "page:"; private FragmentManager mFm; private SparseArray<Fragment> mPages; public CacheFragmentStatePagerAdapter(FragmentManager fm) { super(fm); mPages = new SparseArray<Fragment>(); mFm = fm; } @Override public Parcelable saveState() { Parcelable p = super.saveState(); Bundle bundle = new Bundle(); bundle.putParcelable(STATE_SUPER_STATE, p); bundle.putInt(STATE_PAGES, mPages.size()); if (0 < mPages.size()) { for (int i = 0; i < mPages.size(); i++) { int position = mPages.keyAt(i); bundle.putInt(createCacheIndex(i), position); Fragment f = mPages.get(position); mFm.putFragment(bundle, createCacheKey(position), f); } } return bundle; } @Override public void restoreState(Parcelable state, ClassLoader loader) { Bundle bundle = (Bundle) state; int pages = bundle.getInt(STATE_PAGES); if (0 < pages) { for (int i = 0; i < pages; i++) { int position = bundle.getInt(createCacheIndex(i)); Fragment f = mFm.getFragment(bundle, createCacheKey(position)); mPages.put(position, f); } } Parcelable p = bundle.getParcelable(STATE_SUPER_STATE); super.restoreState(p, loader); } /** * Get a new Fragment instance. * Each fragments are automatically cached in this method, * so you don't have to do it by yourself. * If you want to implement instantiation of Fragments, * you should override {@link #createItem(int)} instead. * * {@inheritDoc} * * @param position position of the item in the adapter * @return fragment instance */ @Override public Fragment getItem(int position) { Fragment f = createItem(position); // We should cache fragments manually to access to them later mPages.put(position, f); return f; } @Override public void destroyItem(ViewGroup container, int position, Object object) { if (0 <= mPages.indexOfKey(position)) { mPages.remove(position); } super.destroyItem(container, position, object); } /** * Get the item at the specified position in the adapter. * * @param position position of the item in the adapter * @return fragment instance */ public Fragment getItemAt(int position) { return mPages.get(position); } /** * Create a new Fragment instance. * This is called inside {@link #getItem(int)}. * * @param position position of the item in the adapter * @return fragment instance */ protected abstract Fragment createItem(int position); /** * Create an index string for caching Fragment pages. * * @param index index of the item in the adapter * @return key string for caching Fragment pages */ protected String createCacheIndex(int index) { return STATE_PAGE_INDEX_PREFIX + index; } /** * Create a key string for caching Fragment pages. * * @param position position of the item in the adapter * @return key string for caching Fragment pages */ protected String createCacheKey(int position) { return STATE_PAGE_KEY_PREFIX + position; } }