Last active
October 18, 2016 11:05
-
-
Save lujop/1f70bda6dec9ef44fb8cd07b89202e9b to your computer and use it in GitHub Desktop.
Minimal changes to FragmentPagerAdapter to make it safe between screen rotations. Some comments at http://stackoverflow.com/questions/19393076/how-to-properly-handle-screen-rotation-with-a-viewpager-and-nested-fragments
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 cat.joanpujol.androidbase.adapter; | |
/* | |
* Copyright (C) 2011 The Android Open Source Project | |
* | |
* 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. | |
*/ | |
import android.os.Parcelable; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.support.v4.app.FragmentStatePagerAdapter; | |
import android.support.v4.app.FragmentTransaction; | |
import android.support.v4.view.PagerAdapter; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import cat.joanpujol.seniorlauncher.error.UnnexpectedStateError; | |
/** | |
* Implementation of {@link android.support.v4.view.PagerAdapter} that | |
* represents each page as a {@link Fragment} that is persistently | |
* kept in the fragment manager as long as the user can return to the page. | |
* | |
* <p>This version of the pager is best for use when there are a handful of | |
* typically more static fragments to be paged through, such as a set of tabs. | |
* The fragment of each page the user visits will be kept in memory, though its | |
* view hierarchy may be destroyed when not visible. This can result in using | |
* a significant amount of memory since fragment instances can hold on to an | |
* arbitrary amount of state. For larger sets of pages, consider | |
* {@link FragmentStatePagerAdapter}. | |
* | |
* <p>When using FragmentPagerAdapter the host ViewPager must have a | |
* valid ID set.</p> | |
* | |
* <p>Subclasses only need to implement {@link #getItem(int)} | |
* and {@link #getCount()} to have a working adapter. | |
* | |
* <p>Here is an example implementation of a pager containing fragments of | |
* lists: | |
* | |
* {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java | |
* complete} | |
* | |
* <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is: | |
* | |
* {@sample development/samples/Support4Demos/res/layout/fragment_pager.xml | |
* complete} | |
* | |
* <p>The <code>R.layout.fragment_pager_list</code> resource containing each | |
* individual fragment's layout is: | |
* | |
* {@sample development/samples/Support4Demos/res/layout/fragment_pager_list.xml | |
* complete} | |
*/ | |
public abstract class SafeFragmentPagerAdapter extends PagerAdapter { | |
private static final String TAG = "FragmentPagerAdapter"; | |
private static final boolean DEBUG = false; | |
private final FragmentManager mFragmentManager; | |
private FragmentTransaction mCurTransaction = null; | |
private Fragment mCurrentPrimaryItem = null; | |
private Integer containerId; | |
public SafeFragmentPagerAdapter(FragmentManager fm) { | |
mFragmentManager = fm; | |
} | |
/** | |
* Return the Fragment associated with a specified position. | |
*/ | |
public Fragment getItem(int position) { | |
if(containerId!=null) { | |
final long itemId = getItemId(position); | |
String name = makeFragmentName(containerId, itemId); | |
return mFragmentManager.findFragmentByTag(name); | |
} else { | |
return null; | |
} | |
} | |
public abstract Fragment createFragment(int position); | |
@Override | |
public void startUpdate(ViewGroup container) { | |
} | |
@Override | |
public Object instantiateItem(ViewGroup container, int position) { | |
if (mCurTransaction == null) { | |
mCurTransaction = mFragmentManager.beginTransaction(); | |
} | |
if(containerId==null) | |
containerId = container.getId(); | |
else if(containerId!=container.getId()) | |
throw new UnnexpectedStateError("Container id not expected to change"); | |
final long itemId = getItemId(position); | |
// Do we already have this fragment? | |
String name = makeFragmentName(container.getId(), itemId); | |
Fragment fragment = mFragmentManager.findFragmentByTag(name); | |
if (fragment != null) { | |
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); | |
mCurTransaction.attach(fragment); | |
} else { | |
fragment = createFragment(position); | |
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); | |
mCurTransaction.add(container.getId(), fragment, | |
makeFragmentName(container.getId(), itemId)); | |
} | |
if (fragment != mCurrentPrimaryItem) { | |
fragment.setMenuVisibility(false); | |
fragment.setUserVisibleHint(false); | |
} | |
return fragment; | |
} | |
@Override | |
public void destroyItem(ViewGroup container, int position, Object object) { | |
if (mCurTransaction == null) { | |
mCurTransaction = mFragmentManager.beginTransaction(); | |
} | |
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object | |
+ " v=" + ((Fragment)object).getView()); | |
mCurTransaction.detach((Fragment)object); | |
} | |
@Override | |
public void setPrimaryItem(ViewGroup container, int position, Object object) { | |
Fragment fragment = (Fragment)object; | |
if (fragment != mCurrentPrimaryItem) { | |
if (mCurrentPrimaryItem != null) { | |
mCurrentPrimaryItem.setMenuVisibility(false); | |
mCurrentPrimaryItem.setUserVisibleHint(false); | |
} | |
if (fragment != null) { | |
fragment.setMenuVisibility(true); | |
fragment.setUserVisibleHint(true); | |
} | |
mCurrentPrimaryItem = fragment; | |
} | |
} | |
@Override | |
public void finishUpdate(ViewGroup container) { | |
if (mCurTransaction != null) { | |
mCurTransaction.commitAllowingStateLoss(); | |
mCurTransaction = null; | |
mFragmentManager.executePendingTransactions(); | |
} | |
} | |
@Override | |
public boolean isViewFromObject(View view, Object object) { | |
return ((Fragment)object).getView() == view; | |
} | |
@Override | |
public Parcelable saveState() { | |
return null; | |
} | |
@Override | |
public void restoreState(Parcelable state, ClassLoader loader) { | |
} | |
/** | |
* Return a unique identifier for the item at the given position. | |
* | |
* <p>The default implementation returns the given position. | |
* Subclasses should override this method if the positions of items can change.</p> | |
* | |
* @param position Position within this adapter | |
* @return Unique identifier for the item at position | |
*/ | |
public long getItemId(int position) { | |
return position; | |
} | |
private static String makeFragmentName(int viewId, long id) { | |
return "android:switcher:" + viewId + ":" + id; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment