In this part of my app, I am trying to implement deleting of selected favorite items via contextual action mode/bar, the problem is when I select an item then delete, it's deleted from the database and selected list but it is still available in recyclerView and it adds a duplicate from another item, the following gif clarify the problem
Here's the FavoritesPostAdapter, I deleted unrelated codes
public class FavoritesPostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final FragmentActivity fragmentActivity;
private final List<FavoritesEntity> favoritesList;
private View rootView;
@Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
}
private static final int CARD = 0;
private static final int CARD_MAGAZINE = 1;
private static final int TITLE = 2;
private static final int GRID = 3;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
public static final String TAG = "POST ADAPTER";
private int viewType;
public final Fragment fragment;
public final PostViewModel postViewModel;
private ActionMode mActionMode;
private boolean multiSelection = false;
// private int selectedPostPosition ;
private final List<FavoritesEntity> selectedPosts = new ArrayList<>();
private final List<RecyclerView.ViewHolder> myViewHolders = new ArrayList<>();
public FavoritesPostAdapter(FragmentActivity fragmentActivity,
List<FavoritesEntity> favoritesList, Fragment fragment,
PostViewModel postViewModel) {
this.fragmentActivity = fragmentActivity;
this.favoritesList = favoritesList;
this.fragment = fragment;
this.postViewModel = postViewModel;
}
public void setViewType(int viewType) {
this.viewType = viewType;
notifyDataSetChanged();
}
public int getViewType() {
return this.viewType;
}
private final ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
mActionMode = actionMode;
actionMode.getMenuInflater().inflate(R.menu.favorites_contextual_menu, menu);
applyStatusBarColor(R.color.contextualStatusBarColor);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return true;
}
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
if (menuItem.getItemId() == R.id.delete_favorites_post) {
for (FavoritesEntity favoritesEntity : selectedPosts) {
postViewModel.deleteFavoritePost(favoritesEntity);
}
showSnackBar(selectedPosts.size() + " post/s deleted");
multiSelection = false;
selectedPosts.clear();
notifyDataSetChanged();
mActionMode.finish();
}
return true;
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
for (RecyclerView.ViewHolder holder : myViewHolders) {
changePostStyle(holder, R.color.cardBackgroundColor, R.color.strokeColor);
}
multiSelection = false;
selectedPosts.clear();
applyStatusBarColor(R.color.statusBarColor);
}
};
private void showSnackBar(String message){
Snackbar.make(rootView,message,Snackbar.LENGTH_SHORT).show();
}
private void applyStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fragmentActivity.getWindow().setStatusBarColor(ContextCompat.getColor(fragmentActivity, color));
}
}
private void applySelection(RecyclerView.ViewHolder holder, FavoritesEntity currentSelectedPost) {
if (selectedPosts.contains(currentSelectedPost)) {
selectedPosts.remove(currentSelectedPost);
changePostStyle(holder, R.color.cardBackgroundColor, R.color.strokeColor);
} else {
selectedPosts.add(currentSelectedPost);
changePostStyle(holder, R.color.cardBackgroundLightColor, R.color.primaryColor);
}
applyActionModeTitle();
}
private void changePostStyle(RecyclerView.ViewHolder holder, int backgroundColor, int strokeColor) {
if (holder instanceof CardViewHolder) {
((CardViewHolder) holder).cardLayoutBinding.mainLinearLayout.setBackgroundColor(
ContextCompat.getColor(fragmentActivity.getApplicationContext(),
backgroundColor)
);
((CardViewHolder) holder).cardLayoutBinding.cardView.setStrokeColor(
strokeColor);
}
}
private void applyActionModeTitle() {
if (selectedPosts.size() == 0) {
mActionMode.finish();
multiSelection = false;
} else if (selectedPosts.size() == 1) {
mActionMode.setTitle(selectedPosts.size() + " item selected");
} else {
mActionMode.setTitle(selectedPosts.size() + " items selected");
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(fragmentActivity);
View view;
if (this.viewType == CARD) {
final CardLayoutBinding cardLayoutBinding
= CardLayoutBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new FavoritesPostAdapter.CardViewHolder(cardLayoutBinding);
} else if (this.viewType == CARD_MAGAZINE) {
final CardMagazineBinding cardMagazineBinding
= CardMagazineBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new FavoritesPostAdapter.CardMagazineViewHolder(cardMagazineBinding);
} else if (this.viewType == TITLE) {
if (SDK_VERSION < Build.VERSION_CODES.LOLLIPOP) {
view = inflater.inflate(R.layout.title_layout_v15, parent, false);
} else {
view = inflater.inflate(R.layout.title_layout, parent, false);
}
return new FavoritesPostAdapter.TitleViewHolder(view);
} else {
if (SDK_VERSION < Build.VERSION_CODES.LOLLIPOP) {
view = inflater.inflate(R.layout.grid_layout_v15, parent, false);
} else {
view = inflater.inflate(R.layout.grid_layout, parent, false);
}
return new FavoritesPostAdapter.GridViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
myViewHolders.add(holder);
rootView = holder.itemView.getRootView();
// selectedPostPosition = position;
int itemType = getViewType();
FavoritesEntity favoriteItem = favoritesList.get(position);
final Document document = Jsoup.parse(favoriteItem.getItem().getContent());
final Elements elements = document.select("img");
// Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
switch (itemType) {
case CARD:
if (holder instanceof FavoritesPostAdapter.CardViewHolder) {
((FavoritesPostAdapter.CardViewHolder) holder).bind(favoriteItem);
((CardViewHolder) holder).cardLayoutBinding.cardView.setOnClickListener(view -> {
if (multiSelection) {
applySelection(holder, favoriteItem);
} else {
mActionMode.finish();
if (Objects.requireNonNull(Navigation.findNavController(
view
).getCurrentDestination()).getId() == R.id.nav_favorites) {
Navigation.findNavController(view)
.navigate(FavoritesFragmentDirections
.actionFavoritesFragmentToDetailsFragment(favoriteItem.getItem()));
}
}
}
);
((CardViewHolder) holder).cardLayoutBinding.cardView.setOnLongClickListener(view -> {
if (!multiSelection) {
multiSelection = true;
fragmentActivity.startActionMode(mActionModeCallback);
applySelection(holder, favoriteItem);
return true;
} else {
applySelection(holder, favoriteItem);
return true;
}
});
}
break;
favorites_contextual_menu xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/delete_favorites_post"
android:title="@string/delete_post"
app:showAsAction="ifRoom"
app:iconTint="@color/white"
android:icon="@drawable/ic_delete"
>
</item>
</menu>
PS: I tried to get the selected position from the holder and assign it to selectedPostPosition int value to use it in notifyItemRemoved(position); and notifyItemRangeChanged(position, getItemCount()); like in this answer but it doesn't fix the issue
from RecyclerView duplicating items after deletion from contextual action mode

No comments:
Post a Comment