Vinay Nagaraj
Vinay Nagaraj

Reputation: 1192

Filtering a recyclerview with a firebaserecycleradapter

I have a RecyclerView with a FirebaseRecyclerAdapter. I want to populate the RecyclerView with a list of names when the user starts typing into the SearchView.

public class SchoolsAdapter extends FirebaseRecyclerAdapter<School, SchoolsAdapter.SchoolViewHolder> {

    public SchoolsAdapter(Query ref) {
        super(School.class, R.layout.item_school, SchoolViewHolder.class, ref);
    }

    @Override
    public void populateViewHolder(SchoolViewHolder schoolViewHolder, School school, int position) {
        schoolViewHolder.name.setText(school.getName());
        schoolViewHolder.address.setText(school.getAddress());
    }

    static class SchoolViewHolder extends RecyclerView.ViewHolder {

        public TextView name;
        public TextView address;

        public SchoolViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.school_item_tview_name);
            address = (TextView) itemView.findViewById(R.id.school_item_tview_address);
        }
    }
}

I'm guessing I need to add a QueryTextListener to the searchview that would update the Query in the adapter. Would this break the FirebaseRecyclerAdapter?

Or should I

@Override
public boolean onQueryTextChange(String newText) {
    mRecyclerView.setAdapter(new SchoolAdapter(ref.orderByChild("name").startAt(userQuery).endAt(userQuery+"~")) 
    return false;
}

whenever the user types something?

Also the docs talk about ordering and sorting firebase queries but don't explicitly say the best way to do string pattern matching. What's the best way to do string matching so that the recycler view shows all results which have the search query as a substring of the database record, and possibly those that are 1 edit distance away as well.

Also a way to ignorecase on queries?

Upvotes: 3

Views: 2864

Answers (1)

kendavidson
kendavidson

Reputation: 1460

I just finished doing something near to what you're looking for, I'm not sure it's the most elegant solution, but I'll throw out some ideas and if you think my idea will help I can definitely provide some examples.

Firstly, when I extended the base FirebaseAdapter I added a new filter named mFullList, since mItems of the FirebaseAdapter will be used for the display list, I don't want to keep going back to the network when I didn't have to. I then override all the methods in my child class to update mFullList with the values from the Firebase callbacks, sort them, filter them then call super.X() with the new list.

Quickly:

public reset(List)
   mFullList = List
   Collections.sort(mFullList, Comparator)
   getFilter().filter(filterString)

The filterString is a field within the Adapter and is updated during the call to getFilter().filter(). During the perform filter I then loop through the mFullList and do a compare of:

mFullList.get(pos).getName().toLowerCase().contains(filterString.toLowerCase);

Once fitlering is done you have a new list that is passed to Filter.publishResults in the FilterResults object. publishResults calls a method in the class that performs the update and notify.

filterCompleted(List)
   getItems().clear
   getItems().addAll
   notify

Essentially, I didn't want the FirebaseAdapater to stop getting the full list of items, I just wanted the users request to filter that full list and handle their request appropriately. Also, I didn't see a point to the added network requests based the user typing an extra character.

Using this method you can just use:

adapter.getFilter().filter("something")

to filter the list based on your updated field, and

adapter.getFilter().filter("")

to reset the full list (as long as your performFilter() handled it correctly. This way new updates from FireBase will be filtered based on the users selection, as well as when a user types in new values, won't require making new Firebase network requests.

Upvotes: 3

Related Questions