Search code examples
javaandroidandroid-recyclerviewsearchview

Searchview in recyclerview duplicates the data


A search view is implemented in action bar, the search works fine, but for example, If user search for two characters pa, my list contains 2 data related to the related to pa i.e., pack1,pack2 then data loads in the recycler view. now if user enter another character l, to the previous characters pa, now my search view has pal , but array list doesn't match with the search, the list doesn't contain any item with pal. i.e., now the recycler view is empty. now, if I clear the character l, the list gets reloaded with data pack1, pack2, but result loads 2 times i.e., instead of showing 2 items in recyclerview, it shows 4 items in total. It is duplicating the items, when the search is cleared.

searchview

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_order, menu);
        searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
        searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
        searchView.setMaxWidth(Integer.MAX_VALUE);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                mOrderAdapter.getFilter().filter(query);
                searchView.clearFocus();
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                if(newText.length()==0){
                    getData();
                    searchView.clearFocus();
                }
                mOrderAdapter.getFilter().filter(newText);
                return true ;
            }
        });
        return true;
    }

Filter code

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                String charString = constraint.toString();
                if (charString.isEmpty()||charString.length()==0) {
                    mListFilter = mOrderArrayList;
                } else {
                    List<Order> filteredList = new ArrayList<>();
                    ArrayList<Order> templist=new ArrayList<Order>();
                    for (Order ord : mOrderArrayList) {
                        if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
                                || ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
                            filteredList.add(ord);
                            templist.addAll(mListFilter);
                        }
                    }
                    mOrderArrayList.removeAll(templist);
                    mOrderArrayList.addAll(filteredList);
                    mListFilter = filteredList;
                }

                FilterResults filterResults = new FilterResults();
                filterResults.values = mListFilter;
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mListFilter = (ArrayList<Order>) results.values;
                notifyDataSetChanged();
            }
        };
    }

Any help is really appreciated.

Adapter code

public class OrderAdapter extends RecyclerView.Adapter<OrderAdapter.MyViewHolder> implements Filterable {

    private Context mContext;
    private List<Order> mListFilter,mOrderArrayList;
    private SharedPreferences sharedPreferences;
    private Resources r;


    public OrderAdapter(Context context, ArrayList<Order> orderList) {
        mContext = context;
        mListFilter = orderList;
        mOrderArrayList = orderList;
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        r = context.getResources();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView orderNoView, itemNameView, qtyView, statusView, companyNameView;
        private Order currentItem;

        MyViewHolder(View view) {
            super(view);
            orderNoView = view.findViewById(R.id.orderNo);
            itemNameView = view.findViewById(R.id.item);
            qtyView = view.findViewById(R.id.qty);
            statusView = view.findViewById(R.id.status);
            companyNameView = view.findViewById(R.id.company);

        }

        void bind (Order om) {  //<--bind method allows the ViewHolder to bind to the data it is displaying
            orderNoView.setText(om.getOs_OrderNo());
            itemNameView.setText(String.valueOf(om.getItemName()));
            qtyView.setText("Qty - " + String.valueOf(om.getOs_Qty()));
            statusView.setText(om.getStatusName());

            if (sharedPreferences.getString(r.getString(R.string.key_CompanyInUser), "").equals("0")){
                companyNameView.setVisibility(View.GONE);
            } else {
                companyNameView.setText(om.getCustomerName());
            }
            currentItem = om; //<-- keep a reference to the current item
        }
    }


    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.adapter_order, parent, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        Order item =  mListFilter.get(position);
        holder.bind(item);

    }

    @Override
    public int getItemCount() {
        return mListFilter.size();
    }


    @Override

    public int getItemViewType(int position){
        return  position;

    }
@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            String charString = constraint.toString();
            List<Order> filteredList = new ArrayList<>();
            if (charString.isEmpty()||charString.length()==0) {
                filteredList.addAll(mOrderArrayList);
            } else {
                for (Order ord : mOrderArrayList) {
                    if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
                            || ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
                        filteredList.add(ord);
                    }
                }
            }
            FilterResults filterResults = new FilterResults();
            filterResults.values = filteredList;
            return filterResults;
        }
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            mListFilter = (ArrayList<Order>) results.values;
            notifyDataSetChanged();
        }
    };
}

}

Clicklistener code

  brandView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), brandView,
                new RecyclerTouchListener.ClickListener() {
                    @Override
                    public void onClick(View view, int position) {
                        isRefreshData = true;
                        startActivity(new Intent(mContext, ViewOrderDetails.class).putExtra("Key-Intent-OrderNo",mOrderArrayList.get(position).getOs_OrderNo()).putExtra("Key-Intent-BrandName",mOrderArrayList.get(position).getos_BrandName()));
                    }
                    @Override
                    public void onLongClick(View view, int position) {
                    }
                }));

Solution

  • Its because you are using addAll inside a loop in #performFiltering . Also why you have two local list for filtering? Check the method below it should work . i have removed the extra code and code which is causing the issue .

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                String charString = constraint.toString();
                List<Order> filteredList = new ArrayList<>();
                if (charString.isEmpty()||charString.length()==0) {
                    filteredList.addAll(mOrderArrayList);
                } else {
                    for (Order ord : mOrderArrayList) {
                        if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
                                || ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
                            filteredList.add(ord);
                        }
                    }
                }
                FilterResults filterResults = new FilterResults();
                filterResults.values = filteredList;
                return filterResults;
            }
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mListFilter = (ArrayList<Order>) results.values;
                notifyDataSetChanged();
            }
        };
    }