FreeFlow icon indicating copy to clipboard operation
FreeFlow copied to clipboard

Invalid index is passed to adapter when notifyDataSetChanged() while scrolling

Open ypresto opened this issue 9 years ago • 2 comments

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.

  1. 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
  2. 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
  3. 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

ypresto avatar Jun 18 '15 08:06 ypresto

Calling moveViewPort() before onMeasure() causes crash.

So flingRunnable is also affected.

ypresto avatar Jun 18 '15 10:06 ypresto

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);
    }

ypresto avatar Jun 19 '15 02:06 ypresto