使用自定义适配器实现过滤器的 ListView 正在获取 IndexOutOfBoundsException

Posted

技术标签:

【中文标题】使用自定义适配器实现过滤器的 ListView 正在获取 IndexOutOfBoundsException【英文标题】:ListView using a custom Adapter to implement a Filter is getting IndexOutOfBoundsException 【发布时间】:2018-10-09 04:36:25 【问题描述】:

我有一个自定义ListView。除非尝试过滤用户搜索,否则它工作正常。

显示ListView的代码:

private void listShow() 
    warranties=db.getAllServWarr();
    adapter=new WarrantyAdapter(serviceswarranty_activity.this,warranties);
    listView.setAdapter(adapter);

在自定义适配器中实现过滤器的代码:

public class WarrantyAdapter extends ArrayAdapter implements Filterable
private ArrayList<ServicesWarranty> warrantyList;
private ArrayList<ServicesWarranty> filteredList;

private ItemFilter mFilter = new ItemFilter();
private Context context;
private int currPosition;
public WarrantyAdapter(@NonNull Context context,ArrayList<ServicesWarranty> warrantyList) 
    super(context, R.layout.serviceswarranty_item,warrantyList);
    this.warrantyList=warrantyList;
    this.filteredList=warrantyList;
    this.context=context;


@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) 
    ServicesWarranty sw=warrantyList.get(position);
    currPosition=position;
    WarrantyAdapter.ViewHolder holder;
    if(convertView==null)
        LayoutInflater inflater=(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView=inflater.inflate(R.layout.serviceswarranty_item,parent,false);
        holder=new WarrantyAdapter.ViewHolder();
        holder.lockno=(TextView)convertView.findViewById(R.id.lockNum_warrantyitem);
        holder.fromdate=(TextView)convertView.findViewById(R.id.fromDate_warrantyItem);
        holder.todate=(TextView)convertView.findViewById(R.id.toDate_warrantyItem);
        holder.editIc=(ImageView)convertView.findViewById(R.id.editic_warrantyItem);
        holder.deleteIc=(ImageView)convertView.findViewById(R.id.deleteic_warrantyItem);
        convertView.setTag(holder);
    else
        holder=(WarrantyAdapter.ViewHolder) convertView.getTag();
    
    holder.fill(sw);
    return convertView;

private class ViewHolder
    public TextView lockno;
    public TextView fromdate;
    public TextView todate;
    public ImageView editIc;
    public ImageView deleteIc;
    public void fill(final ServicesWarranty sw)
        lockno.setText(String.valueOf(sw.getLockNumber()));
        fromdate.setText(sw.getBeginDate());
        todate.setText(sw.getEndDate());
        editIc.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Intent intent=new Intent(context,Add2warranty.class);
                intent.putExtra("AddedWarrantyLockNo",sw.getLockNumber().toString());
                context.startActivity(intent);
            
        );
        deleteIc.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                AlertDialog.Builder deleteAlert=new AlertDialog.Builder(context);
                deleteAlert.setMessage("آیا از حذف گارانتی با شماره قفل "+sw.getLockNumber().toString()+" اطمینان دارید؟")
                        .setPositiveButton("بله", new DialogInterface.OnClickListener() 
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) 
                                AppDBHelper db=new AppDBHelper(context);
                                boolean res=db.deleteFromWarranty(sw.getID());
                                if(res) 
                                    Toast.makeText(context, "Delete successfully", Toast.LENGTH_SHORT).show();
                                    warrantyList.remove(currPosition);
                                    notifyDataSetChanged();
                                

                            
                        )
                        .setNegativeButton("خیر",null)
                        .show();
            
        );
    

public Filter getFilter() 
    return mFilter;


private class ItemFilter extends Filter 
    @Override
    protected FilterResults performFiltering(CharSequence constraint) 

        String filterString = constraint.toString();

        FilterResults results = new FilterResults();

        final List<ServicesWarranty> list = filteredList;

        int count = list.size();
        final ArrayList<ServicesWarranty> nlist = new ArrayList<ServicesWarranty>(count);

        String filterableString ;

        for (int i = 0; i < count; i++) 
            filterableString = list.get(i).getLockNumber().toString();
            if (filterableString.toLowerCase().contains(filterString)) 
                nlist.add(list.get(i));
            
        

        results.values = nlist;
        results.count = nlist.size();

        return results;
    

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) 
        warrantyList = (ArrayList<ServicesWarranty>) results.values;
        notifyDataSetChanged();
    


我还将它添加到我的活动中以启用过滤器搜索

inputSearch.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
        @Override
        public boolean onQueryTextSubmit(String s) 
            return false;
        

        @Override
        public boolean onQueryTextChange(String s) 
            if(s.length()>0)
                adapter.getFilter().filter(s);
            return false;
        
    );

当我调试这个程序时,adapter.getFilter().filter(s); 工作正常,但在接近函数结束时程序强制关闭。

这是我的 logcat 信息

FATAL EXCEPTION: main                                                                  
Process: com.example.zahra.prj1, PID: 18592                                                                        
java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1                                                                            
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)                                                                            
at java.util.ArrayList.get(ArrayList.java:308)

在我的ListView 中,我有 2 个项目,其值为 13 和 14。我在搜索文本框中输入 4,因此列表大小应该是 1。

为什么过滤不起作用?感谢您的帮助。

【问题讨论】:

使用 LogCat 检查与您的崩溃相关的 Java 堆栈跟踪:***.com/questions/23353173/… 谢谢你,我把 logcat 信息添加到我的帖子中 能否贴出getItemCount函数代码 另外我想问一下你为什么还在使用 ListView 而不是 RecyclerView 【参考方案1】:

问题是数组超出范围,因为 getCount() 返回的是保修列表的大小而不是过滤列表。

这里有一个很好的例子来说明如何处理这两个列表: Implementing Filterable

但一般来说,WarrantyAdapter 应该使用过滤列表。 ItemFilter 应该使用warrantyList 来发布filteredList。

您的代码在我的环境中运行,并进行了以下更改:

@Override
public int getCount() 
    return filteredList.size();


@Override
public Object getItem(int position) 
   return filteredList.get(position);


@Override
public long getItemId(int position) 
    return position;

我修改了WarrantyAdapter 以扩展BaseAdapter 和内部getView 我使用filteredList...

【讨论】:

是的,谢谢你我实现了这个方法并且它有效! 太棒了! :) :) :)

以上是关于使用自定义适配器实现过滤器的 ListView 正在获取 IndexOutOfBoundsException的主要内容,如果未能解决你的问题,请参考以下文章

带有过滤器 Android 的自定义 Listview 适配器

使用自定义适配器实现 Expandable ListView

如何用文本图片和复选框过滤自定义listView?

为自定义 ArrayAdapter 实现 Fiterable 接口

在android中过滤和排序ListView的问题

具有自定义适配器的 ListView 中的 SearchView