Search code examples
androidandroid-recyclerviewsearchviewandroid-livedataandroid-viewmodel

How to use Filter SearchView for RecyclerView when using Livedata?


I have a RecyclerView. I want to make it filterable with SearchView. My application is based on Android Architecture Components.

I created a filter method for searchView .When i search something it's work but when i clear text from searchView ,list do not change and still shows search data.

Activity:

    private StudentAdapter mAdapter;

    mAdapter = new StudentAdapter(this);
    recyclerView.setAdapter(mAdapter);

    //ViewModel
    StudentViewModelFactory factory = new StudentViewModelFactory(mDb, mClassId);
    StudentViewModel viewModel = ViewModelProviders.of(this, factory).get(StudentViewModel.class);
    viewModel.getStudentEntries().observe(this, studentEntries -> mAdapter.setStudents(studentEntries));

    //SearchView
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
    @Override
    public boolean onQueryTextSubmit(String query){
            return false;
    }

    @Override
    public boolean onQueryTextChange(String newText){
            mAdapter.getFilter().filter(newText);
            return false;
    }
    });

Adapter:

public class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.itemHolder> {

    private List<StudentEntry> mStudentEntries;
    private List<StudentEntry> filteredStudentEntries;

    public StudentAdapter(Context context) {
        this.context = context;
    }

    public void setStudents(List<StudentEntry> studentEntries) {
        this.mStudentEntries = studentEntries;
        notifyDataSetChanged();
    }

    public void setPerformances(List<PerformanceEntry> performanceEntries) {
        this.mPerformanceEntries = performanceEntries;
        notifyDataSetChanged();
    }
        .
        .
        .

    public Filter getFilter() {
        return new Filter() {
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mStudentEntries = (List<StudentEntry>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                filteredStudentEntries = null;//avaz shod vali test nashod
                if (constraint.length() == 0) {
                    filteredStudentEntries = mStudentEntries;
                } else {
                    filteredStudentEntries = getFilteredResults(constraint.toString().toLowerCase());
                }


                FilterResults results = new FilterResults();
                results.values = filteredStudentEntries;
                return results;
            }
        };
    }

    protected List<StudentEntry> getFilteredResults(String constraint) {
        List<StudentEntry> results = new ArrayList<>();

        for (StudentEntry item : mStudentEntries) {
            if (item.getStudentName().toLowerCase().contains(constraint)
                    || item.getStudentId().toLowerCase().contains(constraint)) {
                results.add(item);
            }
        }
        return results;
    }
}

Solution

  • Change :

    private List<StudentEntry> filteredStudentEntries;
    

    To :

    private ArrayList<StudentEntry> arrayList = new ArrayList<>();
    

    And Change :

    public void setStudents(List<StudentEntry> studentEntries) {
        this.mStudentEntries = studentEntries;
        notifyDataSetChanged();
    }
    

    to :

    public void setStudents(List<StudentEntry> studentEntries) {
        this.mStudentEntries = studentEntries;
        arrayList.addAll(mStudentEntries);
        notifyDataSetChanged();
    }
    

    And change filter method :

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
    
                constraint = constraint.toString().toLowerCase().trim();
                mStudentEntries.clear();
                if (constraint.length() == 0) {
                    mStudentEntries.addAll(arrayList);
                } else {
                    for (StudentEntry item : arrayList) {
                        if (item.getStudentName().toLowerCase(Locale.getDefault()).contains(constraint)
                                || item.getStudentId().toLowerCase(Locale.getDefault()).contains(constraint)) {
                            mStudentEntries.add(item);
                        }
                    }
                }
    
                FilterResults results = new FilterResults();
                results.values = mStudentEntries;
    
                return results;
            }
    
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                notifyDataSetChanged();
            }
        };
    }
    

    And don't forget to implements Filterable in adapter class.