Ошибка при удалении объекта
У меня есть RecyclerView в который поступают данные из phpMyAdmin, я хочу сделать чтобы у каждого элемента была кнопка - "удалить". Для этого я написал такой вот код в моём Adapter.
holder.delete.setOnClickListener(view -> {
int position = holder.getAdapterPosition();
String url = "DELETE.php";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
response -> Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show(),
error -> Log.e("AAAAAAAAA", String.valueOf(error)) ) {
@Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("position", models.get(position).getPosition());
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(stringRequest);
models.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, models.size());
});
Но при удалении последнего объекта появляется ошибка
NetworkDispatcher.processRequest: Unhandled exception java.lang.IndexOutOfBoundsException: Index: 4, Size: 4
Позже я заметил, что при удалении предпоследнего объекта удаляется последний и так происходит со всеми объектами в списке, удаляется на одну позицию выше, то есть я удаляю объект 4 а удаляется объект 5.
В логах ругается на вот эту строку params.put("position", models.get(position).getPosition());
В интернете я узнал, что прописав getAdapterPosition(), проблема должна уйти, но это не сработало, как это исправить?
Ответы (1 шт):
Ваша проблема в том, что запрос асинхронный - он выполняется в другом потоке в другое время.
Это значит что нет никакой гарантии, что методы StringRequest-а и колбеков выполнятся раньше чем код, следующий по тексту после их обявления. Это и происходит - удаление объекта из модели происходит раньше, чем попытка его оттуда взять.
Что можно сделать:
- получить позицию за пределами тела запроса
holder.delete.setOnClickListener(view -> {
int position = holder.getAdapterPosition();
String serverPosition = models.get(position).getPosition();
String url = "DELETE.php";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
response -> Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show(),
error -> Log.e("AAAAAAAAA", String.valueOf(error)) ) {
@Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("position", serverPosition);
return params;
}
};
- перенести удаление объекта и обновление адаптера в колбек. Думаю так будет логичнее - если запрос отвалился и объект на сервере не удалён, то и локально его удалять не следует
holder.delete.setOnClickListener(view -> {
int position = holder.getAdapterPosition();
String url = "DELETE.php";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
response -> {
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();
models.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, models.size());
},
error -> Log.e("AAAAAAAAA", String.valueOf(error)) ) {
@Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("position", models.get(position).getPosition());
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(stringRequest);
});