FreeFlow
FreeFlow copied to clipboard
Invalid index is passed to adapter when notifyDataSetChanged() while scrolling
FreeFlowContainer#notifyDataSetChanged()
calls requestLayout() and redraw with backed adapter (computeLayout() and mLayout.prepareLayout()) in onMeasure().
- https://github.com/Comcast/FreeFlow/blob/96ebb0cc959ba0bfe5d8a8118aa9345550ff58c9/FreeFlow/src/com/comcast/freeflow/core/FreeFlowContainer.java#L276
- https://github.com/Comcast/FreeFlow/blob/96ebb0cc959ba0bfe5d8a8118aa9345550ff58c9/FreeFlow/src/com/comcast/freeflow/core/FreeFlowContainer.java#L255
But when requestLayout() is called while scrolling, onTouchEvent() is called before onMeasure() and it causes crash by IndexOutOfBoundsException in adapter implementation.
Note that ListView effectively avoids this problem by call layoutChildren() before applying scroll to view.
- Set mDataChanged = true in notifyDataSetChanged(). https://github.com/android/platform_frameworks_base/blob/android-5.1.1_r4/core/java/android/widget/AdapterView.java#L809
- Check mDataChanged and call layoutChildren() inTouchMove(). https://github.com/android/platform_frameworks_base/blob/android-5.1.1_r4/core/java/android/widget/AbsListView.java#L3763
- Then redraw views with new data from mAdapter. https://github.com/android/platform_frameworks_base/blob/android-5.1.1_r4/core/java/android/widget/ListView.java#L1561
Calling moveViewPort() before onMeasure() causes crash.
So flingRunnable is also affected.
For workaround extend FreeFlowContainer and call onMeasure() when moveViewport(boolean)
is called.
@SuppressLint("WrongCall") // for call onMeasure() directly instead of measure()
@Override
protected void moveViewport(boolean isInFlingMode) {
if (dataSetChanged) {
// XXX: Workaround for onTouchEvent() could be called between notifyDataSetChanged() and layout update in onMeasure()
// and passing invalid index to adapter. This enforces layout update before applying scroll.
// Refer: https://github.com/Comcast/FreeFlow/issues/85
onMeasure(getWidth() | MeasureSpec.EXACTLY, getHeight() | MeasureSpec.EXACTLY);
}
super.moveViewport(isInFlingMode);
}