从 RecyclerView 中删除消息

Delete a message from the RecyclerView

我有一个发送消息的应用程序。

我想实现删除消息的功能。如果您长时间单击该消息,将出现一个标记的复选框。接下来,用户可以select他想删除的所有消息,然后点击垃圾桶图标。

消息是使用 RecyclerView 实现的。使用 LiveData 和 Room。

这是 ListAdapter 的样子:

package com.mardaunt.telesupp.recyclerview;

import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import com.mardaunt.telesupp.R;
import com.mardaunt.telesupp.room.Message;
import com.mardaunt.telesupp.room.TimeStampConverter;

public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {

    public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback) {
        super(diffCallback);
    }

    @Override
    public int getItemViewType(int position) {
        if (getItem(position).getNature().equals("outgoing"))
            return R.layout.recyclerview_item_outgoing;
        else
            return R.layout.recyclerview_item_incoming;
    }

    @Override
    public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return MessageViewHolder.create(parent, viewType);
    }

    @Override
    public void onBindViewHolder(MessageViewHolder holder, int position) {
        Message current = getItem(position);

        holder.bind(current.getPhone(),
                    current.getText(),
                    TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время.
    }

    public static class MessageDiff extends DiffUtil.ItemCallback<Message> {

        @Override
        public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem == newItem;
        }

        @Override
        public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem.getText().equals(newItem.getText());
        }
    }
}

这是 ViewHolder 的样子:

package com.mardaunt.telesupp.recyclerview;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.mardaunt.telesupp.R;

class MessageViewHolder extends RecyclerView.ViewHolder {
    private final TextView phoneItemView;
    private final TextView messageItemView;
    private final TextView timeItemView;

    private MessageViewHolder(View itemView) {
        super(itemView);
        messageItemView = itemView.findViewById(R.id.text_view_message);
        phoneItemView = itemView.findViewById(R.id.text_view_phone);
        timeItemView = itemView.findViewById(R.id.text_view_time);
    }

    public void bind(String phone, String message, String time) {
        phoneItemView.setText(phone);
        messageItemView.setText(message);
        timeItemView.setText(time);
    }

        //viewType содержит id для нужного layout.
    static MessageViewHolder create(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                    .inflate(viewType, parent, false);
        return new MessageViewHolder(view);
    }
}

请告诉我如何正确启动此任务?如果我没看错的话,我需要在MessageListAdapter class.

中设置一个长按消息的监听器

MainActivity GitHub。

应用程序的工作原型 (apk file)。

你可能想要一个类似 MessageView

的中间对象
    //this will allow each message to be selected individually.
    //the adapter should display MessageViews instead of Messages directly.
    public class MessageView{
        private Message message;
        private boolean isSelected;
        //constructor and getters and setters;
    }
    //set your view holder like this
    class MessageViewHolder extends RecyclerView.ViewHolder {
        private final TextView phoneItemView;
        private final TextView messageItemView;
        private final TextView timeItemView;
        private final Checkbox checkBoxView;
    
        private MessageViewHolder(View itemView) {
            super(itemView);
            messageItemView = itemView.findViewById(R.id.text_view_message);
            phoneItemView = itemView.findViewById(R.id.text_view_phone);
            timeItemView = itemView.findViewById(R.id.text_view_time);
            checkBoxView= itemView.findViewById(R.id.check_box_view);
            checkboxView.setOnCheckedChangeListener((checkbox,checked)=>{
                 messageList.get(getAdapterPosition()).isSelected(checked);
            });
        }
        public void bind(MessageView messageView) {
             phoneItemView.setText(messageView.getMessage().getPhone());
             messageItemView.setText(messageView.getMessage().getMessage());
             timeItemView.setText(TimeStampConverter.getTime(messageView.getMessage().getDate()));
             checkBoxView.setChecked(messageView.isSelected());
        }
    }  
    //call this on the select all check box in your activity/fragment
    public void onSelectAll(boolean selected){
        for(MessageView view : messageList)
             view.isSelected(selected);
        adapter.notifyDataSetChanged();
    }
    //call this on the delete all button click in your activity/fragment
    public void onDeleteSelected(){
       Iterator i = messageList.iterator();
       MessageView messageView;
       while (i.hasNext()) {
          messageView = (MessageView ) i.next();
          if (messageView.isSelected())
            i.remove();
       }
       adapter.notifyDataSetChanged();   
    }

我已经考虑了一段时间可以做什么。 因此,我决定尝试为 RecyclerView 中的每个元素添加复选框,并在 ListAdapter class.

中设置侦听器
public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {

    HelperAdapter helperAdapter;

    public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback, HelperAdapter helperAdapter) {
        super(diffCallback);
        this.helperAdapter = helperAdapter;
    }

    @Override
    public int getItemViewType(int position) {
        if (getItem(position).getNature().equals("outgoing"))
            return R.layout.recyclerview_item_outgoing;
        else
            return R.layout.recyclerview_item_incoming;
    }

    @Override
    public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return MessageViewHolder.create(parent, viewType);
    }

    @Override
    public void onBindViewHolder(MessageViewHolder holder, int position) {
        Message current = getItem(position);

        holder.bind(current.getPhone(),
                    current.getText(),
                    TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время

            // Добавим все view CheckBox в list чтобы скрывать и показывать их по мере необходимости
        helperAdapter.addCheckBox(holder.getMessageCheckBox());

            // Установим слушатель короткого нажатия по сообщению.
        holder.getMessageBox().setOnClickListener(v -> {
            EditText editPhone = helperAdapter.getMainActivity()
                                    .findViewById(R.id.edit_phone);
            editPhone.setText(current.getPhone());
        });

            // Установим слушатель долгого нажатия по сообщению.
        holder.getMessageBox().setOnLongClickListener(v -> {
            helperAdapter.getMainActivity()
                         .findViewById(R.id.trash_button)
                         .setVisibility(View.VISIBLE);
            helperAdapter.getMainActivity()
                    .findViewById(R.id.close_button)
                    .setVisibility(View.VISIBLE);

            for (CheckBox checkBox: helperAdapter.getSetCheckBox())
                checkBox.setVisibility(View.VISIBLE);
            return false;
        });
            // Установим слушатели для чекбоксов, которые переключают переменную isSelected
        holder.getMessageCheckBox().setOnClickListener(v -> {
            current.isSelected = ((CheckBox) v).isChecked();

            helperAdapter.addCheckBox((CheckBox) v);
        });
    }

    public static class MessageDiff extends DiffUtil.ItemCallback<Message> {

        @Override
        public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem == newItem;
        }

        @Override
        public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
            return oldItem.getText().equals(newItem.getText());
        }
    }
}

我还创建了一个辅助 class HelperAdapter 来通过它删除标记的消息。

public class HelperAdapter {

    private static HelperAdapter helperAdapter;
    private MessageViewModel mMessageViewModel;
    private MainActivity mainActivity;
    private final HashSet<CheckBox> listCheckBox = new HashSet<>();

    public void deleteSelected() {
        LiveData<List<Message>> temp = mMessageViewModel.getAllMessages();
        List<Message> allMessages = temp.getValue();

        if (allMessages != null)
        for(Message message: allMessages)
            if(message.isSelected)
                mMessageViewModel.delete(message);

        // Скроем иконку корзины и чекбоксы
        mainActivity.findViewById(R.id.trash_button).setVisibility(View.GONE);
        mainActivity.findViewById(R.id.close_button).setVisibility(View.GONE);
        for (CheckBox checkBox: listCheckBox)
            checkBox.setVisibility(View.GONE);
    }

    public void setMessageViewModel(MessageViewModel messageViewModel){
        mMessageViewModel = messageViewModel;
    }

    public MessageViewModel getMessageViewModel() { return mMessageViewModel; }

    public HashSet<CheckBox> getSetCheckBox() {return listCheckBox;}

    public void addCheckBox(CheckBox checkBox) {
        listCheckBox.add(checkBox);
    }

    public void removeCheckBox(CheckBox checkBox){
        listCheckBox.remove(checkBox);
    }

    public int sizeCheckBox() {return listCheckBox.size();}

    public static HelperAdapter getHelperAdapter(){
        if (helperAdapter == null) helperAdapter = new HelperAdapter();
        return helperAdapter;
    }

    public void setMainActivity(MainActivity mainActivity){
        this.mainActivity = mainActivity;
    }

    public MainActivity getMainActivity() { return mainActivity; }
}

我还为消息添加了一个布尔变量 class:

@Entity(tableName = "messages_table")
public class Message {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String phone;
    private String text;
    private String nature;
    private String service;
    private Date date;

    @Ignore
    public boolean isSelected;   // I added it

    public Message(int id,
                   @NonNull String phone,
                   @NonNull String text,
                   @NonNull String nature,
                   @NonNull String service,
                   @NonNull Date date
                    ) {
        this.id = id;
        this.phone = phone;
        this.text = text;
        this.nature = nature;
        this.service = service;
        this.date = date;
    }

    public int getId(){return this.id;}
    public String getPhone(){return this.phone;}
    public String getText(){return this.text;}
    public String getNature(){return this.nature;}
    public String getService(){return this.service;}
    public Date getDate(){return this.date;}
}

现在我可以为垃圾桶图标设置监听器了:

// ОнКлик для иконки корзины
    public void deleteMessage(View view){
        helperAdapter.deleteSelected();
    }

感谢 LiveData,我不必考虑更新 RecyclerView。 LiveData 删除已删除的消息。

这工作或多或少稳定,但我感觉我搞砸了体系结构并选择了错误的方法。

测试 apk 文件:https://dropmefiles.com/UxPPx