Skip to content

ClassCastException after updateDataSet with StickyHeaders #696

Open
@technicalflaw

Description

I'm having an issue when I update the adapter's data set (via updateDataSet()), but only when sticky headers are enabled, AND a new header is introduced as part of the update, AND a scroll occurs, such that previously sticky header's position changes. I'm not using expandable headers. In addition, it's very hard to reproduce. It can take hours, but eventually it will occur. Here's the stack:

java.lang.ClassCastException: com.myapp.MyHeaderItem$ViewHolder cannot be cast to com.myapp.MySectionedItem$ViewHolder
        at com.myapp.MySectionedItem.unbindViewHolder(AbstractSegmentItem.java:61)
        at eu.davidea.flexibleadapter.FlexibleAdapter.onViewRecycled(FlexibleAdapter.java:1816)
        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.swapHeader(StickyHeaderHelper.java:245)
        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.updateHeader(StickyHeaderHelper.java:162)
        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.updateOrClearHeader(StickyHeaderHelper.java:138)
        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.onScrolled(StickyHeaderHelper.java:64)
        at androidx.recyclerview.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:4961)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4021)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3652)
        at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1888)
        at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:407)
	...
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
        at android.view.Choreographer.doCallbacks(Choreographer.java:580)
        at android.view.Choreographer.doFrame(Choreographer.java:549)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5343)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)

As you can see, when the StickyHeaderHelper manually recycles its sticky header (normally via its scroll handler, as it scrolls out of the view), it thinks its item is a MySectionedItem instance (i.e. a subclass of AbstractSectionableItem , not AbstractHeaderItem. So the ViewHolder passed to AbstractSectionableItem#unbindViewHolder() is that of the header.

As far as I can tell (I'm in no way sure), this is because the StickyHeaderHelper keeps a reference to the ViewHolder for the stuck item, so when the data set is updated, and the time comes to swap out them item (i.e. recycle it), and it requests its position in the adapter (via FlexibleAdapter#onViewRecycled()'s call to RecyclerView.ViewHolder#getAdapterPosition()) it receives the position it was at before the update, which is still a valid index, but no longer referencing the header's actual position in the new data set.

I should also add that my data set is unusual in that its updates tend to be at the head of the list, so new headers tend to be created at index 0, thus offsetting all items after it. If headers were to be created at the end of the list it would be less likely to occur.

As I say, I'm not 100% sure my explanation is correct, but it's the best I can think of. It might also be related to FlexibleAdapter.AdapterDataObserver#updateStickyHeader()'s delayed call to StickyHeaderHelper#updateOrClearHeader(), which might explain why it doesn't happen every time.

I've checked that my item layout ids are unique, and that Object#equals works OK. I think it might be related to issues #568 and #575. Any help (or just a workaround) would be greatly appreciated.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions