While working with the RecyclerView.Adapter
while building my Wingapedia Android app I needed to write a custom filter. Essentially I had two groupings of flavours and temperatures (I have to admit, now that I look back I definitely did some things wrong when designing this, but that's for another post) which I wanted to use to filter the items in the list.
1public class Flavour {2 protected String name;3 protected String description;4 protected boolean isBbq;5 protected boolean isGarlic;6
7 // Setters and getters oh my8}
On the RecyclerView fragment we want to be able to filter on the name or description (entered in an EditText) as well as any of the isBbq or isGarlic flag within the class. If we were just to create a defualt custom filter it would look like this:
1public class FlavourFilter extends Filter {2 @Override3 protected FilterResults performFiltering(CharSequence constraint) {4 for (Flavour f : mItems) {5 if (f.getName().contains(constraint) || f.getDescription().contains(constraint) {6 mFilteredList.add(f);7 }8 }9 }10
11 @Override12 protected void publishResults(CharSequence constraint, FilterResults results) {13 // Use mFilteredList to update mItems14 }15}
This is all well and good for Filters which only search by name and description, but what if we need to pass in and filter on more options within the item? We need to either pass in:
In this particular case I (update: sadly) decided that it would be a good idea to pass a JSON object from my FilterFlavourView
(responsible for selecting different temperatures, toppings, spices, etc). The JSON object contains the items that I'm interested in:
searchString
which is a text based lookup.temperatureFlag
which is the byte flags of temperatures selected.tagList
which is a list of flavour tags.All of which are combined to filter the appropriate list. The performFiltering
method gets replaced with:
1@Override2protected FilterResults performFiltering(CharSequence constraint) {3 FilterResults results = new FilterResults();4
5 // Set the constraint to a valid value6 filterString = (constraint != null) ? constraint.toString() : "";7
8 // There was no Cache set to this adapter so we will return nothing9 // or there was no constraint set so we will return nothing.10 if (constraint == null || constraint.length() == 0) {11 List filtered = new ArrayList(mFullList);12 results.values = filtered;13 results.count = filtered.size();14 return results;15 }16
17 try {18 JSONObject filter = new JSONObject(constraint.toString());19 mSearchString = filter.getString("Search");20 mTemperatureFlag = filter.getInt("Temperatures");21 mTagList = filter.getString("Tags");22 } catch (Exception e) {23 // Attempting to map the JSONObject failed, most likely24 // constraint is just a String25 mSearchString = constraint.toString();26 mTemperatureFlag = 0;27 mTagList = "";28 }29
30 mTags = parseTags();31
32 List<Flavour> filtered = new ArrayList<>();33 boolean foundTag;34 for (Object obj : mFullList) {35 Flavour flavour = (Flavour) obj;36 //Log.v("Filtering", "Flavour " + flavour.toString());37
38 // If Tags were provided in the Search request, check to see if the39 // Tag is associated to the wing Flavour40 foundTag = false;41 if (mTags != null) {42 for (int i = 0; i < mTags.length; i++) {43 if (flavour.getTags().contains(mTags[i])) {44 foundTag = true;45 break;46 }47 }48 } else {49 foundTag = true;50 }51
52 if ( (mSearchString.length() == 053 || flavour.getName().toLowerCase().contains(mSearchString.toLowerCase()))54 && (mTemperatureFlag == Temperature.ALL_TEMPS55 || (flavour.getTemperature().getFilterFlag() & mTemperatureFlag) != 0)56 && foundTag ){57
58 filtered.add(flavour);59 }60 }61
62 results.values = filtered;63 results.count = filtered.size();64
65 return results;66}
The filtered list is now combined with the three lookups that were required: search text, temperature and flavour.
With a combination of All Star Wings going out of business (at least near me) and Google Play requiring a privacy policy (which I didn't have time nor interest in writing) Wingapedia has sadly been removed from the store.
I've had some interest come up in bringing this app back online, although making it customizable for the food industry. I'll probably look into bringing this back up using React Native or Flutter.