Получение ArrayIndex из Bounds Исключение при добавлении новых элементов в список при прокрутке

У меня есть ListView в котором я загружаю данные из SQLite, устанавливая ограничение на 3 данных из SQLite при прокрутке списка, который я использовал AsyncTask для загрузки еще 3 данных из базы данных, но когда загружаются новые данные, это показывает мне ошибку: ArrayIndexOutOfBoundsException .

адаптер:

 public class FarmerAdapter extends BaseAdapter implements Filterable{ Context context; ArrayList<Farmer> farmeritems; ArrayList<Farmer> mStringFilterList; ValueFilter valueFilter; public FarmerAdapter(Context context, ArrayList<Farmer> list) { this.context = context; farmeritems = list; mStringFilterList = list; } @Override public int getCount() { return farmeritems.size(); } @Override public Object getItem(int position) { return farmeritems.get(position); } @Override public long getItemId(int position) { return position; } @Override public int getViewTypeCount() { return getCount(); } @Override public int getItemViewType(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup arg2) { Farmer farmerdetails = farmeritems.get(position); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.model_farmer, null); } final TextView farmname = (TextView) convertView.findViewById(R.id.tv_farmer_name); final TextView farmmobno = (TextView) convertView.findViewById(R.id.tv_farmer_mobno); final TextView farmlocation = (TextView) convertView.findViewById(R.id.tv_farmer_location); final LinearLayout farmtrade = (LinearLayout) convertView.findViewById(R.id.li_farmer_trade); final LinearLayout farmadvance = (LinearLayout) convertView.findViewById(R.id.li_farmer_advance); final ImageView img_trade = (ImageView)convertView.findViewById(R.id.img_farmertrade); final ImageView img_advance = (ImageView)convertView.findViewById(R.id.img_farmeradvance); farmname.setText(farmerdetails.getFarmername()); farmmobno.setText(farmerdetails.getFarmermobno()); farmlocation.setText(farmerdetails.getFarmerlocation()); farmtrade.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { img_trade.setColorFilter(ContextCompat.getColor(context, R.color.colorAccent)); img_advance.clearColorFilter(); Intent b = new Intent(context, Farmer_simpletrade_Activity.class); b.putExtra("fname", farmname.getText().toString()); b.putExtra("fmobno", farmmobno.getText().toString()); context.startActivity(b); } }); farmadvance.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { img_advance.setColorFilter(ContextCompat.getColor(context, R.color.colorAccent)); img_trade.clearColorFilter(); Intent c = new Intent(context, Farmer_simpleadvance_Activity.class); c.putExtra("farmername", farmname.getText().toString()); c.putExtra("farmermobno", farmmobno.getText().toString()); context.startActivity(c); ((Activity) context).finish(); } }); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //todo disable the comments for farmer individual transaction Intent a = new Intent(context, FarmerLedgerView_Activity.class); a.putExtra("farmername", farmname.getText().toString()); a.putExtra("farmermobno", farmmobno.getText().toString()); context.startActivity(a); ((Activity) context).finish(); } }); return convertView; } @Override public Filter getFilter() { if (valueFilter == null) { valueFilter = new ValueFilter(); } return valueFilter; } private class ValueFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint != null && constraint.length() > 0) { ArrayList<Farmer> filterList = new ArrayList<Farmer>(); for (int i = 0; i < mStringFilterList.size(); i++) { if ((mStringFilterList.get(i).getFarmername().toUpperCase()) .contains(constraint.toString().toUpperCase())) { Farmer farmer = new Farmer(mStringFilterList.get(i) .getFarmername(), mStringFilterList.get(i) .getFarmermobno(), mStringFilterList.get(i) .getFarmerlocation()); filterList.add(farmer); } } results.count = filterList.size(); results.values = filterList; } else { results.count = mStringFilterList.size(); results.values = mStringFilterList; } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { farmeritems = (ArrayList<Farmer>) results.values; notifyDataSetChanged(); } } public void setTransactionList(ArrayList<Farmer> newList) { farmeritems = newList; notifyDataSetChanged(); } } 

AsyncTask для загрузки данных из фона:

  private class LoadDataTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { } @Override protected Void doInBackground(Void... params) { if (isCancelled()) { return null; } // Simulates a background task try { Thread.sleep(1000); offSet=offSet+3; if (offSet > totalcount) { loadingMore=false; } else { Log.e("OffsetNo", String.valueOf(offSet)); databasehandler = new DatabaseHandler(getApplicationContext()); farmerlabels = new ArrayList<Farmer>(); String selectQuery = "SELECT * FROM farmercontactlabel ORDER BY farmername COLLATE NOCASE LIMIT " + offSet + ""; SQLiteDatabase db = databasehandler.getReadableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); if (cursor.moveToFirst()) { do { Farmer farmerdetails = new Farmer(); farmerdetails.setFarmername(cursor.getString(1)); farmerdetails.setFarmermobno(cursor.getString(2)); farmerdetails.setFarmerlocation(cursor.getString(3)); list.add(farmerdetails); } while (cursor.moveToNext()); } cursor.close(); db.close(); } } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { fadapter.setTransactionList(list); list_farmer.onLoadMoreComplete(); // fadapter.notifyDataSetChanged(); super.onPostExecute(result); } @Override protected void onCancelled() { // Notify the loading more operation has finished list_farmer.onLoadMoreComplete(); } } 

Структура базы данных:

  String CREATE_FARMERS_TABLE = "CREATE TABLE " + FARMERCONTACT_LABELS + "(" + FARMER_ID + " INTEGER," + FARMER_NAME + " TEXT," + FARMER_MOBNO + " NUMERIC PRIMARY KEY," + FARMER_LOCATION + " TEXT" + ");"; db.execSQL(CREATE_FARMERS_TABLE); 

База данных:

  public ArrayList<Farmer> getAllfarmers(int offset) { ArrayList<Farmer> farmerlabels = new ArrayList<Farmer>(); String selectQuery = "SELECT * FROM " + FARMERCONTACT_LABELS + " ORDER BY farmername COLLATE NOCASE LIMIT " + offset + ""; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); if (cursor.moveToFirst()) { do { Farmer farmerdetails = new Farmer(); farmerdetails.setFarmername(cursor.getString(1)); farmerdetails.setFarmermobno(cursor.getString(2)); farmerdetails.setFarmerlocation(cursor.getString(3)); farmerlabels.add(farmerdetails); } while (cursor.moveToNext()); } cursor.close(); db.close(); return farmerlabels; } 

Ошибка:

 java.lang.ArrayIndexOutOfBoundsException: length=3; index=3 at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:7103) at android.widget.ListView.layoutChildren(ListView.java:1653) at android.widget.AbsListView.onLayout(AbsListView.java:2230) at android.view.View.layout(View.java:16001) at android.view.ViewGroup.layout(ViewGroup.java:5181) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1195) at android.view.View.layout(View.java:16001) 

Solutions Collecting From Web of "Получение ArrayIndex из Bounds Исключение при добавлении новых элементов в список при прокрутке"

Если вы ограничиваете количество строк до 3, последний индекс будет равен 2. Итак, если вы попытаетесь получить по индексу 3, вы получите NullPointerException .

В методе setTransactionList вы заменяете существующий набор данных ( List ) новым объектом и после этого вызываете notifyDataSetChanged() . Возможно, между этими вызовами происходит исключение, поэтому вы заменили набор данных, но recyclerview пытается получить доступ к данным по индексу от старого объекта.

Я предлагаю вам добавить метод:

 public void addAllTransaction(List<Farmer> farmerList) { farmeritems.addAll(farmerList); notifyDataSetChanged(); } 

И используйте addAllTransaction вместо setTransactionList .

Также будет лучше использовать notifyItemInserted вместо notifyDataSetChanged .

Дополнительно проверьте этот вопрос: ArrayIndexOutOfBoundsException при заполнении RecyclerView

Если вы получаете ошибку при извлечении данных из объекта курсора, вы должны использовать имя столбца вместо передачи 1, 2 3. Вы используете индекс столбца жесткого кода для получения значения, вместо этого вы должны использовать имена столбцов, чтобы получить индекс столбца, например, ниже Код:

  Farmer farmerdetails = new Farmer(); farmerdetails.setFarmername(cursor.getString(cursor.getColumnIndex(FARMER_NAME))); farmerdetails.setFarmermobno(cursor.getString(cursor.getColumnIndex(FARMER_MOBNO ))); farmerdetails.setFarmerlocation(cursor.getString(cursor.getColumnIndex(FARMER_LOCATION ))); farmerlabels.add(farmerdetails); 

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

Возможно, список farmeritems управляется вне класса FarmerAdapter. Один из способов предотвращения этого – создать новый ArrayList вместо того, чтобы держать ссылку на него.

Вам нужно будет изменить код в своем конструкторе, чтобы:

farmeritems = new ArrayList<Farmer>(list);

Измените код в методе publishResults на:

farmeritems = new ArrayList<Farmer>((ArrayList<Farmer>) results.values);

И, наконец, измените код в методе setTransactionList на:

farmeritems = new ArrayList<Farmer>(newList);

Надеюсь, что это решит вашу проблему.

Посмотрите на свой код

 public void setTransactionList(ArrayList<Farmer> newList) { farmeritems = newList; notifyDataSetChanged(); } 

Что ты делаешь:

Внутри вашего setTransactionList вы повторно ссылаетесь на свои farmeritems то есть после вызова farmeritems = newList ваших farmeritems есть ссылка newList которая имеет только 3 элемента.

Что ты должен делать:

 public void setTransactionList(ArrayList<Farmer> newList) { farmeritems.addAll(newList); notifyDataSetChanged(); } 

Это добавит newList (3 элемента) в ваш farmeritems . Теперь ваши farmeritems обновляются.

Моя лучшая практика использования адаптера для ListView и RecyclerView, я разделяю данные на два типа. Один для временного использования и другой для окончательного использования.

Пример:

 List<Product> productsFinal = new ArrayList<>(); List<Product> productsTemp = new ArrayList<>(); 

Я использую productsTemp когда хочу внести изменения или изменить данные.

productsTemp.add(new Product()); Или productsTemp.remove(0);

Когда я модифицировал данные, пришло время назначить данные для productsFinal которые используются адаптером. Затем я могу очистить данные в productsTemp чтобы сохранить память.

 ProductAdapter adapter = new ProductAdapter(productsFinal); productsView.setAdapter(adapter); ... productsFinal.addAll(productsTemp); productsTemp.clear(); adapter.notifyDataSetChanged(); 

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

Попробуй это:

 if (cursor.moveToFirst()) { do { Farmer farmerdetails = new Farmer(); farmerdetails.setFarmername(cursor.getString(0)); farmerdetails.setFarmermobno(cursor.getString(1)); farmerdetails.setFarmerlocation(cursor.getString(2)); farmerlabels.add(farmerdetails); } while (cursor.moveToNext()); } 

Ваш массив ограничен до 3, что означает, что если вы пытаетесь получить item[3] будет генерировать ArrayIndexOutOfBoundsException потому что это фактически 4-й элемент. Элементы подсчитываются системой n-1 (0,1,2) для 3 предметов.