Search code examples
androidandroid-recyclerviewandroid-roomandroid-livedata

PagedListAdapter and ItemTouchHelper with Room - How do you update during onMove()


The issue I'm having is that when dragging an item on my RecyclerView, the onMove() callback can not change the actual order of the array of items because that array is managed by PagedListAdapter. If I do it on the DB, this happens on a background thread because Room requires me to do that (and I really should do DB on the background thread anyway), and as you can imagine, that doesn't work well with the dragging of the item.

My understanding of how ItemTouchHelper works is that on onMove() I have to rearrange whatever I want to be shown visually and then I can save to the DB on clearView(). But I can't rearrange on onMove().

This is a simplification of my current code, which works but the visual cues of the drag don't work well.

inner class SwipeCallback() : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {
        override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
            val item1 = getItem(viewHolder.adapterPosition)
            val item2 = getItem(target.adapterPosition)
            if (item1 != null && item2 != null) {
                //BASICALLY JUST SWAPPING THE TWO POSITIONS ON THE OBJECTS but not doing anything with the adapter array because the PagedListAdapter doesn't allow me to modify the array as far I know.
                swapItems(item1,item2)

                }
                return true
            }
            return false
        }

        override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }

        override fun isLongPressDragEnabled(): Boolean {
            return false
        }

        override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
            super.onSelectedChanged(viewHolder, actionState)
            if (actionState == ACTION_STATE_DRAG) {
                viewHolder?.itemView?.alpha = 0.5f
            }
        }

        override fun clearView(recyclerView: RecyclerView,
                               viewHolder: RecyclerView.ViewHolder) {
            super.clearView(recyclerView, viewHolder)

            viewHolder?.itemView?.alpha = 1.0f

            //THIS IS WHERE I UPDATED THE DB, currentList is the PagedListAdapter array. This is an inner class of my PagedListAdapter.
            currentList?.let {updateList(it) }
        }
    }

So how can I make this work visually?

Thanks.


Solution

  • Finally found the right solution.

    On onMove you have to notifyItemMoved(from,to) and then on clearView you actually make the DB move. Depending on what your move involves, you will probably have to store the first from on notifyItemMoved and then calculate where it is being moved to and modify all the times in between on your DB.