Почему я получаю java.lang.IndexOutOfBoundsException, когда пытаюсь получить элемент jsonArray?

В моем приложении у меня есть что-то вроде прикрепления файлов к сообщениям. Эти прикрепленные файлы отображаются в RecyclerView с адаптером. У каждого элемента RV есть своя кнопка для его удаления. Проблема в том, что когда у меня есть два элемента в моем списке, и я пытаюсь удалить 1 элемент, а не 2-й, я получаю сообщение об ошибке. Но когда я пытаюсь удалить 2-й пункт, а затем 1-й, все ок. Я использовал отладчик и мне удалось найти проблемную строку, но я не знаю, как решить эту проблему. Итак, вот код адаптера для удаления элемента из списка:

val array = Singleton.array
if (array!!.size() > 0) {
  for (i in 0 until array.size()) {
   val obj = array.get(i).asJsonObject

   if (obj.get("filename").toString().substring(1, obj.get("filename").toString().length - 1) == mNames[position]) {
   array.remove(obj)
   mNames.removeAt(position)
   Singleton.array = array
   updateNames(mNames)
   }

 }
}

У меня проблема в этой строке:

val obj = array.get(i).asJsonObject

Я проверил через регистратор эту переменную, и все вроде бы в порядке, я могу получить значение с индексом 0. Тогда я подумал, что проблема в том месте, где я отправляю данные на адаптер, но все в порядке. Я использовал отладчик и увидел, что метод getAsJsonObject() выдает это исключение:

Почему я получаю java.lang.IndexOutOfBoundsException, когда пытаюсь получить элемент jsonArray?

почему это происходит и как я могу решить эту ошибку. Я попытался изменить это: for (i in 0 until array.size()) к этому for (i in 0 until array.size()-1) и это не сработало. Потом попробовал поменять этот цикл на этот for (i in 1 until array.size()) и тоже не помогло. Итак, где я допустил ошибку и как я могу предотвратить эту проблему в будущем?

P.S. Извините, что прикрепляю скриншот отладчика, так как не смог получить из него текстовые данные.

Нумерация элементов в Java/Kotlin 0...length-1поэтому, если размер вашего массива равен 10, вы можете получить из него 0...9 элементов. Проверьте свое for (i in 0 until array.size()) { состояние

Vladyslav Matviienko 30.05.2019 08:19

Вы удаляете элемент из массива, перебирая его, поэтому его размер изменяется. Попробуйте удалить напрямую из Singleton.array или сделайте копию массива для итерации и удалите из оригинала.

Arun 30.05.2019 08:22

@ Арун, можешь проверить мой ответ, пожалуйста? может это решит мою проблему?

Andrew 30.05.2019 08:27

@VladyslavMatviienko, я увидел, что проблема связана с процессом удаления элемента из массива, это означает, что мой цикл продолжается, когда я уже удалил его элемент, поэтому я решил использовать прерывание/возврат из цикла при удалении элемента, мой ответ показывает этот метод

Andrew 30.05.2019 08:29

@AndrewGoroshko Я думаю, ваш ответ должен работать, пока вы удаляете только один элемент.

Arun 30.05.2019 08:33

@VladyslavMatviienko, но я не могу удалить несколько элементов, только один элемент без удаления группы

Andrew 30.05.2019 08:34

@AndrewGoroshko почему? ты можешь я уверен

Vladyslav Matviienko 30.05.2019 08:35

@VladyslavMatviienko, почему ты уверен? Я могу удалить элемент, когда нажимаю кнопку удаления, и я могу удалить только один элемент из списка? Я не могу отметить несколько пунктов :)

Andrew 30.05.2019 08:39

@AndrewGoroshko ты имеешь в виду ты не можешь или ты не хочешь? Потому что я не вижу препятствий для удаления нескольких элементов

Vladyslav Matviienko 30.05.2019 08:45

Я не могу, я уверен, и меня также удивляет, что вы уверены, потому что мне также интересно, как удалить несколько элементов :) например, когда у меня уже есть некоторые элементы, которые приходят из черновика сообщения и для удаление файла черновика я должен отправить запрос также на сервер

Andrew 30.05.2019 08:50

Какой класс array? Если это коллекция, вы можете использовать метод array.removeAll(<collection to remove>) для удаления нескольких элементов. Также, как показано Rajasekaran M, вы можете использовать цикл для удаления нескольких элементов.

Vladyslav Matviienko 30.05.2019 13:36

логически подтверждено, что я не могу удалить несколько элементов, один клик = один элемент

Andrew 30.05.2019 13:39
2
12
464
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Дорогие друзья, кажется, мне удалось решить эту проблему, но я не уверен, поэтому мне нужна ваша проверка. Итак, я добавил оператор возврата в свое условие:

if (obj.get("filename").toString().substring(1, obj.get("filename").toString().length - 1) == mNames[position]) {
array.remove(obj)
mNames.removeAt(position)
Singleton.array = array
updateNames(mNames)
return@setButton
}

поэтому, когда я встречаю это условие, я возвращаюсь из процесса удаления. Я думаю, что я знаю, почему мое приложение иногда дает сбой - я нажимаю да в моем диалоговом окне предупреждения, и мой объект был удален из массива, но мой цикл продолжает работать и проверять. Но может я опять ошибаюсь :)

просто используйте оператор break, братан.

Jeeva 30.05.2019 08:21

куда? вместо возврата?

Andrew 30.05.2019 08:23

да, вы используете этот код для кнопки удаления, которая будет использоваться один раз сразу после удаления, почему вы должны продолжать повторять цикл for. Просто используйте break после выполнения условия if

Jeeva 30.05.2019 08:24

а мой способ может решить эту проблему или пользователи выше тоже давали полезные советы?

Andrew 30.05.2019 08:25

Я бы предложил вам поступить иначе: вместо на лету удаления элементов из массива сначала собрать элементы, которые нужно удалить, в другой массив, и только после цикла - удалить элементы.

Vladyslav Matviienko 30.05.2019 08:32

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

Jeeva 30.05.2019 08:35
Ответ принят как подходящий

Вы удалили элемент из исходного массива, поэтому вы получаете исключение, поэтому используйте новый массив для отфильтрованных значений.

Проблема в нижней строке

array.remove(obj)

Решение :

val positionsForRemove = ArrayList<Int>(),
val array = Singleton.array
if (array!!.size() > 0) {
   for (i in 0 until array.size()) {
     val obj = array.get(i).asJsonObject
     if (obj.get("filename").toString().substring(1, obj.get("filename").toString().length - 1) == mNames[position]) 
       positionsForRemove.add(position)
    }
   for(position in positionsForRemove){
          array.remove(position)
          mNames.remove(position)   
        }
  Singleton.array = array
  updateNames(mNames)


}

Итак, где я могу вставить это новое использование массива?

Andrew 30.05.2019 08:24

Объявите новый массив или MutableList и добавьте в него все элементы массива. и новыйСписок.удалить(объект); и вы можете восстановить его на своем синглтоне после завершения цикла for

Rajasekaran M 30.05.2019 08:26

а как насчет возврата после удаления элемента массива? это может мне помочь? или объявление массива лучше?

Andrew 30.05.2019 08:30

да, я обновил ответ, теперь попробуйте с ним. for loop {был неуместен. теперь это сработает для вас

Rajasekaran M 30.05.2019 08:57

так это лучше, чем мое решение, которое я разместил ниже? ваше решение также работает хорошо, но почему оно лучше?

Andrew 30.05.2019 09:12

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

Rajasekaran M 30.05.2019 09:19

Просто добавьте оператор break в условие if.

val array = Singleton.array
if (array!!.size() > 0) {
  for (i in 0 until array.size()) {
   val obj = array.get(i).asJsonObject

   if (obj.get("filename").toString().substring(1, obj.get("filename").toString().length - 1) == mNames[position]) {
   array.remove(obj)
   mNames.removeAt(position)
   Singleton.array = array
   updateNames(mNames)
   break;
   }

 }
}

Причина, по которой вы получаете исключение после удаления первого элемента, заключается в том, что цикл выполняется после удаления первого элемента. цикл заканчивается ровно после удаления второго элемента.

Вы используете метод удаления внутри итерации цикла for, который динамически изменяет размер массива.

Если вам нужно удалить только один элемент, обратитесь к ответу @Jeeva.

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

val removePositions = ArrayList<Int>(),
val array = Singleton.array
if (array!!.size() > 0) {
  for (i in 0 until array.size()) {
   val obj = array.get(i).asJsonObject

   if (obj.get("filename").toString().substring(1, obj.get("filename").toString().length - 1) == mNames[position])
   //array.remove(obj)
   //mNames.removeAt(position)
   removePositions.add(position)
   //Singleton.array = array
   //updateNames(mNames)
  }

  for (i in 0 until removePositions.size()) {
    array.remove(removePositions[i])
    mNames.remove(removePositions[i])
  }
  Singleton.array = array
  updateNames(mNames)
}

@AndrewGoroshko, какую ошибку вы получаете с приведенным выше кодом?

DHAVAL A. 30.05.2019 08:59

@AndrewGoroshko, извините, код был немного неуместен. Теперь попробуйте с фиксированным кодом.

DHAVAL A. 30.05.2019 09:06

Другие вопросы по теме