ViewPager data set change fixes
Clean up ViewPager data set change operations a bit and update
FragmentPagerAdapter to allow for items changing positions within the
adapter during a data set change.
Bug 6347192
Change-Id: Ib0aaa31190fca561f9b2c6c94f37e0b5eb1d1e90
diff --git a/v13/java/android/support/v13/app/FragmentPagerAdapter.java b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
index dcd6f22..60aa5d0 100644
--- a/v13/java/android/support/v13/app/FragmentPagerAdapter.java
+++ b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
@@ -89,17 +89,19 @@
mCurTransaction = mFragmentManager.beginTransaction();
}
+ final long itemId = getItemId(position);
+
// Do we already have this fragment?
- String name = makeFragmentName(container.getId(), position);
+ String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
- if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment);
+ if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
- if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
+ if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
- makeFragmentName(container.getId(), position));
+ makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
FragmentCompat.setMenuVisibility(fragment, false);
@@ -114,7 +116,7 @@
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
- if (DEBUG) Log.v(TAG, "Detaching item #" + position + ": f=" + object
+ if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
@@ -158,7 +160,20 @@
public void restoreState(Parcelable state, ClassLoader loader) {
}
- private static String makeFragmentName(int viewId, int index) {
- return "android:switcher:" + viewId + ":" + index;
+ /**
+ * 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;
}
}
\ No newline at end of file
diff --git a/v4/java/android/support/v4/app/FragmentPagerAdapter.java b/v4/java/android/support/v4/app/FragmentPagerAdapter.java
index 6a5ecc3..01ca411 100644
--- a/v4/java/android/support/v4/app/FragmentPagerAdapter.java
+++ b/v4/java/android/support/v4/app/FragmentPagerAdapter.java
@@ -85,17 +85,19 @@
mCurTransaction = mFragmentManager.beginTransaction();
}
+ final long itemId = getItemId(position);
+
// Do we already have this fragment?
- String name = makeFragmentName(container.getId(), position);
+ String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
- if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment);
+ if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
- if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
+ if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
- makeFragmentName(container.getId(), position));
+ makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
@@ -110,7 +112,7 @@
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
- if (DEBUG) Log.v(TAG, "Detaching item #" + position + ": f=" + object
+ if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
@@ -154,7 +156,20 @@
public void restoreState(Parcelable state, ClassLoader loader) {
}
- private static String makeFragmentName(int viewId, int index) {
- return "android:switcher:" + viewId + ":" + index;
+ /**
+ * 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;
}
}
diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java
index 5220d30..73b16b1 100644
--- a/v4/java/android/support/v4/view/ViewPager.java
+++ b/v4/java/android/support/v4/view/ViewPager.java
@@ -685,7 +685,8 @@
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
- boolean needPopulate = mItems.size() < 3 && mItems.size() < mAdapter.getCount();
+ boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
+ mItems.size() < mAdapter.getCount();
int newCurrItem = -1;
boolean isUpdating = false;
@@ -712,6 +713,7 @@
if (mCurItem == ii.position) {
// Keep the current item in the valid range
newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
+ needPopulate = true;
}
continue;
}
@@ -743,15 +745,8 @@
lp.widthFactor = 0.f;
}
}
- }
- if (newCurrItem >= 0) {
- // TODO This currently causes a jump.
- setCurrentItemInternal(newCurrItem, false, true);
- needPopulate = true;
- }
- if (needPopulate) {
- populate();
+ populate(newCurrItem);
requestLayout();
}
}