I've got an implementation where a SharedFlow is observed, and on change, the observed model is passed to the Epoxy controller (setData is called). The view models themselves don't rebind, but the view models are built and the diff gets run. My main question is - does something else happen with the RecyclerView, layout manager or the adapter when the controller is building the view models?
The reason I'm asking is that I have some other code initiating some scrolling relatively quickly (on a button pressed) after the setData is called:
val smoothScroller =
object : LinearSmoothScroller(this.context) {
override fun getVerticalSnapPreference(): Int = snapMode
}
smoothScroller.targetPosition = position
layoutManager?.startSmoothScroll(smoothScroller)
This scrolling works fine 80% of the time, but for the other 20% it fails to find the next item and begins scrolling through the whole RecyclerView, until finding the right item or giving up in a random position. If I remove my observable and no longer call setData before startSmoothScroll, the bug goes away. If I add a delay (even 50ms works) before initiating the scrolling, the bug goes away. So my theory is that the RecyclerView is doing something that prevents the scroller to operate correctly. I added some additional debugging in the scroller and saw that when everything works file, RecyclerView.SmoothScroller goes through this path of the code:
if (mTargetView != null) {
// verify target position
if (getChildPosition(mTargetView) == mTargetPosition) {
onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
and when the issue occurs, it falls into:
if (mRunning) {
onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);
Considering I don't see the log message Passed over target position while smooth scrolling., I think mTargetView is null when the scroller attempts to scroll. However I'm not sure why it would get into that state and why a 50ms delay would make any difference.
I've got an implementation where a
SharedFlow
is observed, and on change, the observed model is passed to the Epoxy controller (setData
is called). The view models themselves don't rebind, but the view models are built and the diff gets run. My main question is - does something else happen with theRecyclerView
, layout manager or the adapter when the controller is building the view models?The reason I'm asking is that I have some other code initiating some scrolling relatively quickly (on a button pressed) after the
setData
is called:This scrolling works fine 80% of the time, but for the other 20% it fails to find the next item and begins scrolling through the whole
RecyclerView
, until finding the right item or giving up in a random position. If I remove my observable and no longer callsetData
beforestartSmoothScroll
, the bug goes away. If I add a delay (even 50ms works) before initiating the scrolling, the bug goes away. So my theory is that theRecyclerView
is doing something that prevents the scroller to operate correctly. I added some additional debugging in the scroller and saw that when everything works file,RecyclerView.SmoothScroller
goes through this path of the code:and when the issue occurs, it falls into:
Considering I don't see the log message
Passed over target position while smooth scrolling.
, I thinkmTargetView
is null when the scroller attempts to scroll. However I'm not sure why it would get into that state and why a 50ms delay would make any difference.