notifyItemMoved () не работает при переходе на ListAdapter Android

У нас есть эта функция в нашем приложении, где мы можем перетаскивать элементы просмотра переработчика вверх и вниз.

Внутри onMove () ItemTouchHelper.Callback () мы вызываем

adapter.onItemMove(source.adapterPosition, target.adapterPosition)

и код адаптера выглядит так

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
    Collections.swap(dataList, fromPosition, toPosition)
    notifyItemMoved(fromPosition, toPosition)
    return true
}

Теперь, более ранний класс адаптера расширял RecyclerView.Adapter (), и у нас есть следующий метод для обновления нашего списка с помощью DiffUtils

fun setDataList(feeds: List<User>): DiffUtil.DiffResult {
    val diffResult = DiffUtil.calculateDiff(ContentDiffCall(mFeeds, feeds))
    this.mFeeds.clear()
    this.mFeeds.addAll(feeds)
    return diffResult
}

Перетаскивание с этим отлично работало.

Но когда мы расширили наш класс адаптера из ListAdapter, уже работающая функциональность (перетаскивание) перестала работать. Первый элемент в представлении ресайклера не перетаскивается за пределы второго элемента, а также не обновляется положение перетаскиваемого элемента.

Отмена реализации ListAdapter заставляет его снова работать.

Не могу понять, почему это не работает, когда ListAdapter сам расширяет RecyclerView.Adapter.

Класс адаптера

class ContentListAdapter(
private val headerListener: HeaderClickListener?,
private val listener: ListItemClickListener?,
private val screen: Screen,
private val feedInteractor: FeedInteractionManager
) : ListAdapter<BaseUiModel, RecyclerView.ViewHolder>(ContentListDiffCall()), ContentTouchHelperAdapter {

private var dataList = ArrayList<BaseUiModel>()

init {
    setHasStableIds(true)
}

fun setDataList(data: List<BaseUiModel>) {
    dataList.clear()
    dataList.addAll(data)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
        HFType.CONTENT_LIST_HEADER.ordinal -> ContentListHeaderViewHolder.getInstance(
            parent,
            headerListener,
            R.layout.layout_content_list_header,
            screen
        )
        HFType.SONG.ordinal -> SongViewHolder.getInstance(parent, listener)
        else -> throw RuntimeException("there is no type that matches the type $viewType ; make sure your using types correctly")

    }
}

override fun getItemViewType(position: Int): Int {
    return getItem(position).hfType.ordinal
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val data = getItem(position)
    when (holder) {
        is SongViewHolder -> {
            if (data is SongUiModel) {
                holder.bindViews(data)
            }
        }
        is ContentListHeaderViewHolder -> {
            if (data is HeaderUiModel) {
                holder.bindViews(data)
            }
        }
    }
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>) {
    if (payloads.isEmpty()) {
        onBindViewHolder(holder, position)
        return
    }
    val data = getItem(position)
    when (holder) {
        is SongViewHolder -> {
            if (data is SongUiModel) {
                holder.bindViews(data, payloads)
            }
        }
        is ContentListHeaderViewHolder -> {
            if (data is HeaderUiModel) {
                holder.bindViews(data, payloads)
            }
        }
    }
}

override fun getItemId(position: Int): Long {
    val data = getItem(position)
    return data.hashCode().toLong()
}

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
    Collections.swap(dataList, fromPosition, toPosition)
    notifyItemMoved(fromPosition, toPosition)
    return true
}

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
    super.onViewAttachedToWindow(holder)
    if (holder is HomeFeedViewHolder<*>) {
        holder.onHolderAttachedInViewPort()
    }
}

}

interface ContentTouchHelperAdapter {
      fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
}

Фрагмент кода внутри фрагмента

private fun setUpRecyclerView() {
    rv_item_list.apply {
        layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        recycledViewPool.setMaxRecycledViews(HFType.SONG.ordinal, 12)
     recycledViewPool.setMaxRecycledViews(HFType.CONTENT_LIST_HEADER.ordinal, 1)
    }

    val spaceItemDecorator = ContentListSpaceDecorator(25.dpToPx())
    rv_item_list.addItemDecoration(spaceItemDecorator)

    adapter = ContentListAdapter(this, this, this, screen, this)
    rv_item_list.adapter = adapter

    val callback = SimpleTouchListener(adapter, contentListViewModel)
    itemTouchHelper = ItemTouchHelper(callback)
    itemTouchHelper.attachToRecyclerView(rv_item_list)

  }

SimpleTouchListener класс

class SimpleTouchListener(
    private val listAdapter: ContentListAdapter,
    private val viewModel: ContentListViewModel
) :
    ItemTouchHelper.Callback() {
    private var fromPosition: Int? = null
    private var toPosition: Int? = null

    override fun isLongPressDragEnabled(): Boolean {
        return false
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return false
    }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        var dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
        if (viewHolder is ContentListHeaderViewHolder) {
            dragFlags = 0
        }
        return makeMovementFlags(dragFlags, 0)         
    }

    override fun onMove(
        recyclerView: RecyclerView,
        source: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        if (source.itemViewType != target.itemViewType) {
            return false
        }
        if (fromPosition == null) {
            fromPosition = source.adapterPosition
        }
        toPosition = target.adapterPosition
        listAdapter.onItemMove(source.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, i: Int) {
        // Notify the adapter of the dismissal
    }

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
            if (viewHolder is ItemTouchHelperViewHolder) {
                val itemViewHolder = viewHolder as ItemTouchHelperViewHolder?
                itemViewHolder?.onItemSelected()
            }
        }
        super.onSelectedChanged(viewHolder, actionState)
    }

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        if (viewHolder is ItemTouchHelperViewHolder) {
            // Tell the view holder it's time to restore the idle state
            val itemViewHolder = viewHolder as ItemTouchHelperViewHolder
            itemViewHolder.onItemClear()
        }
        if (fromPosition != null && toPosition != null) {
            //This method updates the list ordering in DB 
            viewModel.onContentPositionChange(fromPosition, toPosition)
        }
        fromPosition = null
        toPosition = null
    }
}

мы вызываем setAdapterMethod из наблюдателя на Success

private fun setAdapterData(contentList: List<BaseUiModel>?) {
    contentList?.let { it ->
        adapter.setDataList(it)
        adapter.submitList(it)
    }
}

person shalini    schedule 26.11.2019    source источник
comment
Вы обновляете список с помощью функции submitList в ListAdapter?   -  person Bracadabra    schedule 26.11.2019
comment
@Bracadabra да.   -  person shalini    schedule 27.11.2019
comment
Тогда не могли бы вы предоставить полный код, потому что сейчас непонятно, как вы используете свой адаптер   -  person Bracadabra    schedule 27.11.2019
comment
вызывает адаптер.setDataList (список) и адаптер.submitList (список), когда данные успешно получены из источника данных. Я тоже добавил дополнительный код.   -  person shalini    schedule 27.11.2019
comment
Извините, но я не видел вызова submitList в предоставленных фрагментах, если вы посмотрите на источники ListAdapter, вы увидите, что вам следует обновить базовый список с помощью вызова submitList   -  person Bracadabra    schedule 27.11.2019
comment
добавлен метод, который устанавливает данные, полученные от наблюдателя. Но проблема в том, что я думаю, что дальше notifyItemMoved дело не идет.   -  person shalini    schedule 27.11.2019
comment
Добавление setSubmitList (dataList) и удаление notifyItemMoved () в onItemMove () заставляет его работать. Спасибо @Bracadabra   -  person shalini    schedule 27.11.2019
comment
Круто, чем копирую комментарий в ответ, чтобы не оставлять вопрос открытым   -  person Bracadabra    schedule 27.11.2019


Ответы (1)


ListAdapter обновляет свое содержимое с помощью submitList функции:

/**
* Submits a new list to be diffed, and displayed.
* <p>
* If a list is already being displayed, a diff will be computed on a background thread, which
* will dispatch Adapter.notifyItem events on the main thread.
*
* @param list The new list to be displayed.
*/
public void submitList(@Nullable List<T> list) {
    mDiffer.submitList(list);
}

Тогда вы можете просто позвонить:

listAdapter.submitList(updatedList)
person Bracadabra    schedule 27.11.2019