javaandroidandroid-recyclerviewsearchviewandroid-filterable

How to update android RecyclerView items after search filter?


I am trying to filter a RecyclerView using Android Filterable class.

I've followed this tutorial Android RecyclerView adding Search Filter to get this task done.

The project runs without errors, I displayed the result array in log and I'm getting correct results but nothing changes in UI.

Here is my adapter code :

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

private Context mContext ;
private ArrayList<Picture> mData ;
private ArrayList<Picture> mDataFiltered;

public CoffretPicturesAdapter(Context mContext, ArrayList<Picture> mData) {
    this.mContext = mContext;
    this.mData = mData;
    this.mDataFiltered = mData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view ;
    LayoutInflater mInflater = LayoutInflater.from(mContext);
    view = mInflater.inflate(R.layout.cardview_item_coffret,parent,false);
    return new MyViewHolder(view);
}

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            String charString = charSequence.toString();
            if (charString.isEmpty()) {
                mDataFiltered = mData;
            } else {
                ArrayList<Picture> filteredList = new ArrayList<>();
                for (Picture row : mData) {

                    // name match condition. this might differ depending on your requirement
                    // here we are looking for name or phone number match
                    if (row.getTitle().toLowerCase().contains(charString.toLowerCase())) {
                        filteredList.add(row);
                    }
                }

                mDataFiltered = filteredList;
            }

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

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            mDataFiltered = (ArrayList<Picture>) filterResults.values;
            notifyDataSetChanged();
        }
    };
}

@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
    holder.coffret_title.setText(mData.get(position).getTitle());
    Picasso.with(mContext).load(mData.get(position).getUri()).placeholder(R.drawable.placeholder).resize(500,500).centerCrop().into(holder.coffret_thumbnail);
    holder.cardView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mContext, "" + mData.get(position).getTitle(), Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(mContext, SelectedPicPreviewActivity.class);
            intent.putExtra("image_url", mData.get(position).getUri().toString());
            mContext.startActivity(intent);

        }
    });
}

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

public static class MyViewHolder extends RecyclerView.ViewHolder {

    TextView coffret_title;
    ImageView coffret_thumbnail;
    LinearLayout cardView ;

    public MyViewHolder(View itemView) {
        super(itemView);

        coffret_title = (TextView) itemView.findViewById(R.id.coffret_title_id) ;
        coffret_thumbnail = (ImageView) itemView.findViewById(R.id.coffret_img_id);
        cardView = (LinearLayout) itemView.findViewById(R.id.cardview_id);

    }
}

}

Here is the function to get data from my external storage

  private ArrayList<Picture> getData() {
    ArrayList<Picture> results= new ArrayList<>();
    //TARGET FOLDER
    File picsFolder = new File(Environment.getExternalStorageDirectory() + "/coffretPics");

    Picture s;

    if (picsFolder.exists()) {
        //GET ALL FILES IN DOWNLOAD FOLDER
        File[] files = picsFolder.listFiles();

        //LOOP THRU THOSE FILES GETTING NAME AND URI
        for (int i = files.length - 1; i >= 0; i--) {
            File file = files[i];

            s = new Picture();
            s.setTitle(file.getName());
            s.setUri(Uri.fromFile(file));


            results.add(s);
        }
    }

    return results;
}

And this is the function to listen to text input changes

   @Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);

    // Associate searchable configuration with the SearchView
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.action_search)
            .getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));
    searchView.setMaxWidth(Integer.MAX_VALUE);

    // listening to search query text change
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            // filter recycler view when query submitted
            adapter.getFilter().filter(query);
            return false;
        }

        @Override
        public boolean onQueryTextChange(String query) {
            // filter recycler view when text is changed
            adapter.getFilter().filter(query);
            return false;
        }
    });
    return true;
}

I hope you guys can help me to solve this problem.


Solution

  • Your recyclerview isn't working with the filtered data.
    When you finish filtering and call notifyDataSetChanged(); it actually binds all the visible views with the new content, with onBindViewHolder method.
    You can see that in onBindViewHolder you are getting the item from mData when you should get it from mDataFiltered.