使ArrayIndex超出界限在滚动时向列表中添加新项目时出现异常

时间:2017-01-17 11:18:06

标签: android sqlite listview scrollview indexoutofboundsexception

我有一个ListView,我在SQLite中加载数据,方法是在滚动列表时从SQLite设置3个数据的限制我使用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)

7 个答案:

答案 0 :(得分:1)

如果您将行数限制为3,则最后一个索引将为2.因此,如果您尝试获取索引3,则会得到NullPointerException

答案 1 :(得分:0)

setTransactionList方法中,您将使用新对象替换现有数据集(List),然后调用notifyDataSetChanged()。可能在这些调用之间发生异常,因此您替换了数据集,但recyclelerview尝试通过旧对象的索引访问数据。

我建议你添加方法:

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

并使用addAllTransaction代替setTransactionList

最好使用notifyItemInserted代替notifyDataSetChanged

另外,请检查此问题:ArrayIndexOutOfBoundsException when populating RecyclerView

答案 2 :(得分:0)

如果从游标对象检索数据时出错,则应使用列名而不是传递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);

如果指定的列名在表中可用,那么列索引永远不会出错。

答案 3 :(得分:0)

在FarmerAdapter类之外可能正在操作farmeritems列表。防止这种情况的一种方法是创建一个新的ArrayList,而不是保留它的引用。

您必须将构造函数中的代码更改为:

farmeritems = new ArrayList<Farmer>(list);

将方法publishResults中的代码更改为:

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

最后将方法setTransactionList中的代码更改为:

farmeritems = new ArrayList<Farmer>(newList);

希望它能解决你的问题。

答案 4 :(得分:0)

查看您的代码

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中添加farmeritems(3项)。现在,您的farmeritems已更新。

答案 5 :(得分:0)

试试这个:

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个项目。

答案 6 :(得分:0)

我对ListView和RecyclerView使用Adapter的最佳做法, 我将数据分为两种类型。一个用于临时使用,另一个用于最终使用。

示例:

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

希望这个简单的解决方案有助于解决用户在列表上滚动时更新新数据的问题。