Daniel Bank
Daniel Bank

Reputation: 3899

attachToRecyclerView doesn't remove previous ItemHelper from RecyclerView

I have a RecyclerView which has swipe gestures for deleting rows. The RecyclerView's adapter data gets reset from time to time, in which case I reassign its adapter to a new one. While the new data seems to reflect in the UI (i.e. the RecyclerView updates), the swipe gestures still reflect the old adapter. I was expecting that attachToRecyclerView() would be handling the removal of the old ToucherHelper. Per the documentation for attachToRecyclerView():

Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already attached to a RecyclerView, it will first detach from the previous one. You can call this method with null to detach it from the current RecyclerView.

However, my logging shows that the address of the adapter is still that of an older adapter when the onSwiped() is called.

Logs

HistorySwipeHelper init itemCount 0 address 156969509
HistorySwipeHelper init itemCount 3 address 65479865
onSwiped itemCount 0 adapterPosition 0 address 156969509

setupRecyclerView() in MyFragment

private fun setupRecyclerView(historyList: MutableList<HistoryObject>) {
    val historyListAdapter = HistoryListAdapter(historyList)
    val callback = HistorySwipeHelper(historyListAdapter)
    val helper = ItemTouchHelper(callback)
    history_games_list.adapter = historyListAdapter
    helper.attachToRecyclerView(history_games_list)
}

HistorySwipeHelper

class HistorySwipeHelper(private val adapter: HistoryListAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
    init {
        Log.d("HistorySwipeHelper", "HistorySwipeHelper init itemCount ${adapter.itemCount} address ${System.identityHashCode(adapter)}")
    }
    
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        Log.d("HistorySwipeHelper", "onSwiped itemCount ${adapter.itemCount} adapterPosition ${viewHolder.adapterPosition} address ${System.identityHashCode(adapter)}")
        if (viewHolder.adapterPosition < adapter.itemCount) {
            adapter.showMenu(viewHolder.adapterPosition)
        }
    }
}

I can make a member variable on the Fragment which stores a reference to the current ItemHelper and detach it before attaching the new one. This works but it feels like a code-smell. Is there an idiomatic way I should be keeping my swipe gestures in sync with the RecyclerView to which they're attached?

Upvotes: 0

Views: 332

Answers (1)

Spectator
Spectator

Reputation: 332

try attach RecyclerView manually

class HistorySwipeHelper(private val adapter: HistoryListAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
    init {
        Log.d("HistorySwipeHelper", "HistorySwipeHelper init itemCount ${adapter.itemCount} address ${System.identityHashCode(adapter)}")
    }
    
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        Log.d("HistorySwipeHelper", "onSwiped itemCount ${adapter.itemCount} adapterPosition ${viewHolder.adapterPosition} address ${System.identityHashCode(adapter)}")
        if (viewHolder.adapterPosition < adapter.itemCount) {
            adapter.showMenu(viewHolder.adapterPosition)
        }
    }
}.attachToRecyclerView(yourRecyclerView);

Upvotes: 1

Related Questions