Проблема: OnSwipe() не использует последние данные. Все работает до тех пор, пока я не выполню действие конкретно в WorkStartFragment (например, удаление упражнения, перетаскивание), после чего добавлю наборы, а затем удалю добавленный набор. Это вызывает ошибку IndexOutOfBounds, поскольку адаптер пытается удалить элемент, которого нет в переменной set. Более того, сам видхолдер остается неподвижным после выполнения действия в WorkoutStartFragment, а затем немедленно удаляет наборы. Приведенные ниже упражнения не перемещаются вверх.
Демонстрация
Проведение набора вызывает эту функцию в SetAdapter (что приводит к сбой)
Код: Выделить всё
fun removeSet(position: Int) {
if (position < 0 || position >= sets.size) {
Log.e("SetAdapter", "Invalid position: $position, sets.size: ${sets.size}")
return
} //Avoid crashing
sets.removeAt(position)
completions.removeAt(position)
renumberSets()
notifyItemRemoved(position)
notifyItemRangeChanged(position, sets.size)
listener.onSetRemoved(sets)
}
Код: Выделить всё
class SetAdapter(
val sets: MutableList,
private val completions: MutableList,
private val listener: OnSetChangeListener,
private val areCheckboxesEnabled: Boolean
) : RecyclerView.Adapter() {
interface OnSetChangeListener {
fun onSetChanged(setIndex: Int, weight: Float, reps: Int)
fun onSetRemoved(updatedSets: List)
fun onSetTypeChanged(setIndex: Int, setType: String)
fun onSetCompletionChanged(setIndex: Int, isComplete: Boolean)
}
журналы пролистывания показывают, что наборы setAdapter являются наборами непосредственно перед тем, как происходит действие в WorkStartFragment, но журналы добавления наборов показывают эти наборы были добавлены. Ниже приведены примеры, поясняющие это.
Код: Выделить всё
holder.setsRecyclerView.adapter = setAdapter
holder.setsRecyclerView.layoutManager = LinearLayoutManager(holder.itemView.context)
// Enable drag-and-drop and swipe-to-delete for sets
val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val setPosition = viewHolder.bindingAdapterPosition
Log.d("ItemTouchHelper", "onSwiped - Position: $setPosition, sets before remove: ${setAdapter.sets}")
setAdapter.removeSet(setPosition)
Log.d("ItemTouchHelper", "onSwiped - sets after remove: ${setAdapter.sets}")
}
}
val itemTouchHelper = ItemTouchHelper(itemTouchHelperCallback)
itemTouchHelper.attachToRecyclerView(holder.setsRecyclerView)
holder.addSetButton.setOnClickListener {
workoutExercise.weights.add(0.0f)//default value
workoutExercise.reps.add(0)
val setNumber = (workoutExercise.sets.size + 1).toString()
workoutExercise.sets.add(setNumber)
workoutExercise.completion.add(false)
sets.add(Triple(0.0f, 0, setNumber))
setAdapter.notifyItemInserted(sets.size - 1)
Log.d("ItemTouchHelper", "add set button: ${setAdapter.sets}")
}
Код: Выделить всё
val sets = workoutExercise.weights.zip(workoutExercise.reps).mapIndexed { index, pair ->
Triple(pair.first, pair.second, workoutExercise.sets.getOrNull(index) ?: "")
}.toMutableList()
if (workoutExercise.completion.size < sets.size) {
for (i in workoutExercise.completion.size until sets.size) {
workoutExercise.completion.add(false)
}
}
val setAdapter = SetAdapter(
sets, workoutExercise.completion,
object : SetAdapter.OnSetChangeListener {
override fun onSetChanged(setIndex: Int, weight: Float, reps: Int) {
if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION) {
workoutExercise.weights[setIndex] = weight
workoutExercise.reps[setIndex] = reps
}
}
override fun onSetRemoved(updatedSets: List) {
if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION) {
workoutExercise.sets.clear()
workoutExercise.weights.clear()
workoutExercise.reps.clear()
updatedSets.forEach { (weight, reps, setType) ->
workoutExercise.weights.add(weight)
workoutExercise.reps.add(reps)
workoutExercise.sets.add(setType)
}
}
}
override fun onSetTypeChanged(setIndex: Int, setType: String) {
if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION) {
workoutExercise.sets[setIndex] = setType
}
}
override fun onSetCompletionChanged(setIndex: Int, isComplete: Boolean) {
if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION) {
workoutExercise.completion[setIndex] = isComplete
}
if (isComplete) {
onCheckboxChecked(workoutExercise)
}
}
},
areCheckboxesEnabled = checkboxFlag
)
В упражнении 5 подходов, и упражнение перетаскивается.
Пример проблемы 1: добавлено 3 набора, поэтому всего должно быть 8 наборов. Журналы прокрутки показывают (после удаления 8-го набора (не произошел сбой, потому что я добавил код для его предотвращения)) осталось 5 наборов (что верно). Журналы добавления показывают, что после добавления имеется 8 наборов.
Пример проблемы 2: наборы не добавляются, а пятый набор удаляется. Журналы пролистывания показывают, что осталось 4 подхода, и пользовательский интерфейс тоже это показывает, но viewHolder остается неподвижным, и все приведенные ниже упражнения не перемещаются вверх. Если я добавлю набор, приложение аварийно завершает работу java.lang.IndexOutOfBoundsException: Индекс: 5, Размер: 5.
Важное примечание
Удаление наборов само по себе это не проблема. Удаление наборов работает, когда из WorkoutStartFragment ничего не происходит, но также, когда я предоставляю эту функцию другим функциям, таким как кнопки, удаление наборов также работает абсолютно нормально, поэтому функция работает как положено. Проблема возникает из-за пролистывания.
Мне нужно выяснить причину этой проблемы и найти общее решение. Любая помощь или понимание приветствуются. Дайте мне знать, если потребуется дополнительный контекст или код.
Подробнее здесь: https://stackoverflow.com/questions/787 ... g-old-data
Мобильная версия