Any time I insert an item into my Room database, my recycler view flashes the row containing the newly inserted view holder (the rest of the list does not flash). I am using LiveData to keep my list automatically updated by calling submitList(list) in onChanged() of the observed ViewModel method. My adapter extends ListAdapter and I am using DiffUtil to track changes in the list. That being said, I don't call notifyItemInserted(position) directly as DiffUtil should do this for me. There are 2 instances where an item gets inserted (1) a completely new item gets inserted at the end of the list (2) a deleted item gets reinserted into the list. Both cases the item will insert itself then flash. I have read numerous posts where people suggest disabling animations on the recycler view but this is not an option for me as I rely on animations elsewhere in my code. Any other suggestions would be appreciated. I'm trying to keep the posted code brief but I can post more if it would be helpful.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initComponents();
initRecyclerView();
setListeners();
setListObserver();
createItemTouchHelper();
}
private void setListObserver() {
viewModel.getAllItems().observe(this, new Observer<List<ListItem>>() {
@Override
public void onChanged(List<ListItem> newList) {
adapterMain.submitList(newList);
}
});
}
...
// Inserts a new ListItem when MainActivity's EditText is used
public void onClick(View v) {
if (v.getId() == R.id.img_add_item_main) {
String itemName = String.valueOf(edtAddItem.getText());
if (!itemName.trim().equals("")) { // Insert new list item only if the EditText is not empty
ListItem item = new ListItem();
item.setItemName(itemName);
viewModel.insert(item);
}
...
// SnackBar to allow a user to undo a delete operation
public void showUndoSnackBar(ListItem deletedItem) {
Snackbar undoSnackBar = Snackbar.make(constraintLayout, "Undo deleted Item",
Snackbar.LENGTH_LONG).setAction("UNDO", new View.OnClickListener() {
@Override
public void onClick(View v) {
// Restore deleted item to its original position in the list if UNDO is clicked
viewModel.insert(deletedItem);
}
});
undoSnackBar.show();
}
RecyclerAdapterMain.java
public class RecyclerAdapterMain extends ListAdapter<ListItem, RecyclerAdapterMain.ListItemHolder> {
public RecyclerAdapterMain() {
super(DIFF_CALLBACK);
}
private static final DiffUtil.ItemCallback<ListItem> DIFF_CALLBACK = new DiffUtil.ItemCallback<ListItem>() {
@Override
public boolean areItemsTheSame(@NonNull ListItem oldItem, @NonNull ListItem newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull ListItem oldItem, @NonNull ListItem newItem) {
return oldItem.equals(newItem);
}
@Override
public ListItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item_layout_main, parent, false);
return new ListItemHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ListItemHolder holder, int position) {
ListItem item = getItem(position);
holder.txtItemName.setText(item.getItemName());
holder.checkBox.setChecked(item.getIsChecked());
if(item.getIsChecked()) {
holder.txtItemName.setTextColor(Color.LTGRAY);
} else {
holder.txtItemName.setTextColor(Color.BLACK);
}
}
...
ListItem.java (POJO)
@Entity(tableName = "list_item_table")
public class ListItem {
@PrimaryKey(autoGenerate = true)
private long id;
private String itemName;
private boolean isChecked;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
... other getters and setters
public boolean equals(@Nullable ListItem listItem) {
return this.itemName.equals(listItem.getItemName()) && this.isChecked == listItem.getIsChecked();
}
}