Merge "Fix AdapterHelper update/notify order" into oc-mr1-support-27.0-dev
diff --git a/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.java b/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.java
index 3518540..963d047 100644
--- a/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.java
+++ b/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.java
@@ -21,6 +21,7 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -289,6 +290,64 @@
assertFalse(helper.getCurrentList().isImmutable());
}
+ @Test
+ public void itemCountUpdatedBeforeListUpdateCallbacks() {
+ // verify that itemCount is updated in the helper before dispatching ListUpdateCallbacks
+
+ final int[] expectedCount = new int[] { 0 };
+ // provides access to helper, which must be constructed after callback
+ final PagedListAdapterHelper[] helperAccessor = new PagedListAdapterHelper[] { null };
+
+ ListUpdateCallback callback = new ListUpdateCallback() {
+ @Override
+ public void onInserted(int position, int count) {
+ assertEquals(expectedCount[0], helperAccessor[0].getItemCount());
+ }
+
+ @Override
+ public void onRemoved(int position, int count) {
+ assertEquals(expectedCount[0], helperAccessor[0].getItemCount());
+ }
+
+ @Override
+ public void onMoved(int fromPosition, int toPosition) {
+ fail("not expected");
+ }
+
+ @Override
+ public void onChanged(int position, int count, Object payload) {
+ fail("not expected");
+ }
+ };
+
+ PagedListAdapterHelper<String> helper = createHelper(callback, STRING_DIFF_CALLBACK);
+ helperAccessor[0] = helper;
+
+ PagedList.Config config = new PagedList.Config.Builder()
+ .setPageSize(20)
+ .build();
+
+
+ // in the fast-add case...
+ expectedCount[0] = 5;
+ assertEquals(0, helper.getItemCount());
+ helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 5), 0));
+ assertEquals(5, helper.getItemCount());
+
+ // in the slow, diff on BG thread case...
+ expectedCount[0] = 10;
+ assertEquals(5, helper.getItemCount());
+ helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 10), 0));
+ drain();
+ assertEquals(10, helper.getItemCount());
+
+ // and in the fast-remove case
+ expectedCount[0] = 0;
+ assertEquals(10, helper.getItemCount());
+ helper.setList(null);
+ assertEquals(0, helper.getItemCount());
+ }
+
private void drainExceptDiffThread() {
boolean executed;
do {
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
index 0007a2e..abcff41 100644
--- a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
+++ b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
@@ -118,6 +118,8 @@
* @param <T> Type of the PagedLists this helper will receive.
*/
public class PagedListAdapterHelper<T> {
+ // updateCallback notifications must only be notified *after* new data and item count are stored
+ // this ensures Adapter#notifyItemRangeInserted etc are accessing the new data
private final ListUpdateCallback mUpdateCallback;
private final ListAdapterConfig<T> mConfig;
@@ -236,21 +238,25 @@
final int runGeneration = ++mMaxScheduledGeneration;
if (pagedList == null) {
- mUpdateCallback.onRemoved(0, getItemCount());
+ int removedCount = getItemCount();
if (mPagedList != null) {
mPagedList.removeWeakCallback(mPagedListCallback);
mPagedList = null;
} else if (mSnapshot != null) {
mSnapshot = null;
}
+ // dispatch update callback after updating mPagedList/mSnapshot
+ mUpdateCallback.onRemoved(0, removedCount);
return;
}
if (mPagedList == null && mSnapshot == null) {
// fast simple first insert
- mUpdateCallback.onInserted(0, pagedList.size());
mPagedList = pagedList;
pagedList.addWeakCallback(null, mPagedListCallback);
+
+ // dispatch update callback after updating mPagedList/mSnapshot
+ mUpdateCallback.onInserted(0, pagedList.size());
return;
}
@@ -296,10 +302,14 @@
throw new IllegalStateException("must be in snapshot state to apply diff");
}
- PagedStorageDiffHelper.dispatchDiff(mUpdateCallback,
- mSnapshot.mStorage, newList.mStorage, diffResult);
+ PagedList<T> previousSnapshot = mSnapshot;
mPagedList = newList;
mSnapshot = null;
+
+ // dispatch update callback after updating mPagedList/mSnapshot
+ PagedStorageDiffHelper.dispatchDiff(mUpdateCallback,
+ previousSnapshot.mStorage, newList.mStorage, diffResult);
+
newList.addWeakCallback(diffSnapshot, mPagedListCallback);
}