7

Mam ListView, w którym ładuję dane z SQLite, ustawiając limit 3 danych z SQLite podczas przewijania listy Użyłem AsyncTask do załadowania kolejnych 3 danych z bazy danych, ale po załadowaniu nowych danych pokazuje mi błąd: ArrayIndexOutOfBoundsException.Uzyskiwanie ArrayIndex poza granicami Wyjątek podczas dodawania nowych pozycji do listy podczas przewijania

Adapter:

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 załadować dane z tłem:

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(); 
    } 
} 

struktury bazy danych:

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); 

Baza:

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; 
} 

Błąd:

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) 
+0

w twoim AsyncTask gdzie jest zadeklarowana zmienna 'list', która jest używana w' liście.add (informacje o rolniku); 'Proszę również określić, co robisz w metodzie' onLoadMoreComplete() '. – Alex

+0

proszę pokazać, gdzie zostało zadeklarowane i zainicjowane 'list' i' offset' –

Odpowiedz

1

Jeśli ograniczenie liczby wierszy do 3, ostatni wskaźnik będzie 2. Jeśli więc postarać się o indeks 3, otrzymasz NullPointerException.

+2

Wystarczy spojrzeć na moje edytowane pytanie, w którym zawarłem strukturę tabeli, a także w moim kwerendzie wybierającym użyłem Select *, z którego zwraca wszystkie wiersze od stołu do otrzymam tylko nazwę farmy, mobileno i lokalizację użyłem cursor.getString (1), aby uzyskać farmername, cursor.getString (2), aby uzyskać mobileno i cursor.getString (3), aby uzyskać lokalizację –

+0

Jak zaktualizować wartość przesunięcia po asynchronizacji zadanie zostało zakończone. –

+0

"Więc jeśli spróbujesz dostać się przez indeks 3, dostaniesz NullPointerException." Jak widać z edytowanej odpowiedzi, w tabeli znajdują się 4 pola. Tak więc 'getString (3)' nie powinno powodować 'NullPointerException'. – Vusal

0

Metodą, w której zastępujesz istniejący zestaw danych (List) nowym obiektem i po tym wywołaniu notifyDataSetChanged(). Możliwe, wyjątek dzieje się między tymi wywołaniami, więc zastąpiono dataset, ale recyclerview próbuje uzyskać dostęp do danych przez indeks ze starego obiektu.

Proponuję, aby dodać metodę:

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

i używać addAllTransaction zamiast setTransactionList.

Również lepiej będzie użyć notifyItemInserted zamiast notifyDataSetChanged.

Dodatkowo sprawdź to pytanie: ArrayIndexOutOfBoundsException when populating RecyclerView

0

Jeśli otrzymujesz błąd podczas pobierania danych z obiektu kursora, należy użyć nazwy kolumny zamiast przekazywać 1, 2 3. Używasz indeks kolumny hard-kodu, aby uzyskać wartość raczej należy użyć nazwy kolumn, aby uzyskać indeks kolumny jak poniższy kod:

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); 

Podoba Ci się to nigdy nie dostać złego indeks kolumny czy określona nazwa kolumna jest dostępna w tabeli.

0

Może lista farmeritems jest manipulowana poza klasą FarmerAdapter. Jednym ze sposobów zapobiegania jest utworzenie nowej tablicy ArrayList zamiast utrzymywania jej odniesienia.

Trzeba by zmienić kod w swoim konstruktorze do:

farmeritems = new ArrayList<Farmer>(list);

zmienić kod w metodzie publishResults do:

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

I wreszcie zmienić kod w swoim metoda setTransactionList do:

farmeritems = new ArrayList<Farmer>(newList);

Mam nadzieję, że rozwiąże to Twój problem.

0

Spójrz na kodzie

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

Co robisz:

wewnątrz setTransactionList jesteś ponownie Twego farmeritems czyli po wywołaniu farmeritems = newList, twój farmeritems ma odniesienie newList który ma tylko 3 przedmioty.

Co należy zrobić:

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

Spowoduje to dodanie newList (3 pozycje) w farmeritems. Teraz twoja wersja farmeritems jest zaktualizowana.

0

Spróbuj tego:

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()); 
} 

macierzy jest ograniczona do 3, co oznacza, że ​​jeśli próbuje item[3] wygeneruje ArrayIndexOutOfBoundsException bo to jest rzeczywiście pozycja 4-th. Przedmioty liczone są przez system n-1 (0,1,2) dla 3 przedmiotów.

0

Moja najlepsza praktyka używania adaptera zarówno dla ListView, jak i RecyclerView, Rozdzielam dane na dwa typy. Jeden do użytku tymczasowego i drugi do końcowego zastosowania.

Przykład:

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

używam productsTemp gdy chcę dokonać zmian lub modyfikacji danych.

productsTemp.add(new Product()); lub productsTemp.remove(0);

Kiedy zrobiłem modyfikowanie danych, nadszedł czas, aby przypisać dane productsFinal który jest używany przez adapter. Następnie mogę wyczyścić dane w productsTemp, aby zaoszczędzić pamięć.

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

Mam nadzieję, że to proste rozwiązanie pomoże rozwiązać problem aktualizacji danych podczas przewijania listy użytkowników.