I'm attempting to implement a search feature for an app which populates attendees from Firebase. The 'meeting' object has an integer list, containing user IDs, and the application goes to firebase and creates 'user' objects for each user attending that particular meeting.
I'm trying to include a search feature which will help filter and find users based on their name.
Here's where the user objects are being retrieved, and added to the recyclerview as chips:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Integer selectedUser = mMeeting.getUsers().get(position);
String selectedUserString = String.valueOf(selectedUser);
FirebaseFirestore db = FirebaseFirestore.getInstance();
String user = FirebaseAuth.getInstance().getCurrentUser().getUid();
DocumentReference userDocRec = db.collection("users/"+user+"/clients").document(selectedUserString);
userDocRec.get()
.addOnSuccessListener((documentSnapshot) -> {
if (documentSnapshot.exists()) {
User thisUser = documentSnapshot.toObject(User.class);
String name = String.valueOf(thisUser.getFirstName()
+ " " + String.valueOf(thisUser.getSurName()));
String dateOfBirth = thisUser.getDateOfBirth();
Chip chip = ((Chip) holder.itemView);
chip.setChipText(name);
chip.setVisibility(View.VISIBLE);
chip.setChecked(mMeeting.getAttended().contains(selectedUser));
chip.setOnCloseIconClickListener(view -> {
Toast.makeText(mContext, name + " - DOB: " + dateOfBirth, Toast.LENGTH_SHORT).show();
});
userMap.put(position, thisUser);
}
}
).addOnFailureListener((e) -> {
Toast.makeText(mContext, "Cannot load user", Toast.LENGTH_SHORT).show();
}
);
I have tried a pretty hacky solution whereby the adapter and recyclerviews are reloaded every time the search feature is interacted with, and a for loop only populates chips where the user name matches or includes the search term:
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
searchFilter = s;
AttendanceAdapter2 adapter = new AttendanceAdapter2(mMeeting, mContext,
(m) -> ((Callback<Meeting>) getActivity()).update(m));
recyclerView.setAdapter(adapter);
return false;
}
@Override
public boolean onQueryTextChange(String s) {
searchFilter = s;
AttendanceAdapter2 adapter = new AttendanceAdapter2(mMeeting, mContext,
(m) -> ((Callback<Meeting>) getActivity()).update(m));
recyclerView.setAdapter(adapter);
return false;
}
});
if (InterventionAttendanceFragment.searchFilter == "" ||
name.toLowerCase().contains(InterventionAttendanceFragment.searchFilter.toLowerCase())){
Chip chip = ((Chip) holder.itemView);
chip.setChipText(name);
chip.setVisibility(View.VISIBLE);
chip.setChecked(mMeeting.getAttended().contains(selectedUser));
chip.setOnCloseIconClickListener(view -> {
Toast.makeText(mContext, name + " - DOB: " + dateOfBirth, Toast.LENGTH_SHORT).show();
});
}
Its not a great solution, and is very resource heavy, going via firebase every time, and also leaves gaps in the recyclerview, for the chips that don't match the search term.
I have found a few nice solutions, but they rely on the 'users' being populated via a list, and due to the existing infrastructure, and nature of the application, I can't change it too much, to start running off lists rather than firebase:
How to filter a RecyclerView with a SearchView
https://www.androidhive.info/2017/11/android-recyclerview-with-search-filter-functionality/
Any help or pointers, and possible alternative solutions or libraries would be much appreciated!
Currently running Android Studio 3.1.4