I'm using Firestore to hold documents representing people with a name. I'm using a RecyclerView to display them, populating it with Cards that display the names pulled from Firestore. I've implemented a swipe-to-delete feature, which deletes the person from Firestore when you swipe that person's card left or right in the RecyclerView.
My problem is that swiping a card does not cause the RecyclerView to update - when I check Firestore, the deletion does happen, but the RecyclerView just shows a gap where that card used to be. None of the cards below the removed card "move up" to fill the gap.
Inside of onCreate() for the activity that contains the RecyclerView, I call a function called setUpRecyclerView(). Here is that function, which contains the code for swiping:
private void setUpRecyclerView() {
// create the query who's results you want to populate the recyclerView with
Query query = clientsReference.orderBy("lastNameLowercase")
.orderBy("firstNameLowercase");
// how we get the query into the adapter
FirestoreRecyclerOptions<Client> options = new FirestoreRecyclerOptions.Builder<Client>()
.setQuery(query, Client.class)
.build();
// assign the adapter
adapter = new ClientAdapter(options);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
/**
* This section handles what happens when you swipe an item in the recyclerView list
*/
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
adapter.deleteClient(position);
//adapter.notifyItemRemoved(position);
}
}).attachToRecyclerView(recyclerView);
/**
* This section handles what happens when you click on an item in the recyclerView list
*/
adapter.setOnItemClickListener(new ClientAdapter.OnItemClickListener() {
@Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
Client client = documentSnapshot.toObject(Client.class);
String id = documentSnapshot.getId();
Intent intentDisplayClient = new Intent(MainActivity.this, DisplayClientActivity.class);
// Pass ahead the client's id from Firestore to the next activity
intentDisplayClient.putExtra(KEY_ID, id);
startActivity(intentDisplayClient);
}
});
}
And here is the adapter class:
public class ClientAdapter extends FirestoreRecyclerAdapter<Client, ClientAdapter.ClientHolder> {
private OnItemClickListener listener;
/**
* Create a new RecyclerView adapter that listens to a Firestore Query.
*/
public ClientAdapter(@NonNull FirestoreRecyclerOptions<Client> options) {
super(options);
}
@Override
protected void onBindViewHolder(@NonNull ClientHolder holder, int position, @NonNull Client model) {
String lastNameWithComma = model.getLastName() + ", ";
holder.textViewLastName.setText(lastNameWithComma);
holder.textViewFirstName.setText(model.getFirstName());
}
@NonNull
@Override
public ClientHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.client_list_item, parent, false);
return new ClientHolder(v);
}
public void deleteClient(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
class ClientHolder extends RecyclerView.ViewHolder {
TextView textViewLastName;
TextView textViewFirstName;
public ClientHolder(@NonNull View itemView) {
super(itemView);
textViewLastName = itemView.findViewById(R.id.rv_tv_last_name);
textViewFirstName = itemView.findViewById(R.id.rv_tv_first_name);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION && listener != null) {
listener.onItemClick(getSnapshots().getSnapshot(position), position);
}
}
});
}
}
public interface OnItemClickListener {
void onItemClick(DocumentSnapshot documentSnapshot, int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
}
You'll notice that there's a line commented out in the onSwiped() function inside of setUpRecyclerView(). When that line is used, other undesired behavior happens: the RecyclerView DOES "move up" lower cards to fill the gap left behind by the removed card, but whichever card is at the bottom of the RecyclerView gets duplicated and placed at the bottom. So if it looks like this:
A B C D
...and I swipe away C, then it looks like this:
A B D D
So I'm stuck with either the list not updating at all, or updating in a weird way that makes no sense.
If you're interested, I'm following this tutorial to the letter, and it isn't working:
https://www.youtube.com/watch?v=dTuhMFP-a1g&list=PLrnPJCHvNZuAXdWxOzsN5rgG2M4uJ8bH1&index=6&t=0s