如何使用MVP从RecyclerView插入/删除项目

时间:2016-09-30 14:08:24

标签: android architecture android-recyclerview mvp

在MVP中使用Recycler视图时,你们在哪里保留对列表的引用?我有ChatManager可以与不同的主持人交谈。我保留了两份邮件副本,一份在ChatManager,另一份在Presenter。适配器,视图和演示者共享相同的列表。 我在Presenter中引用消息列表的原因是因为我有一些用于删除和滚动的业务逻辑,我想从演示者处理它。

所以现在当我必须删除一条消息时,演示者决定删除哪个项目并将其从列表中删除。现在需要让视图知道消息已被删除。那么在这种情况下,它应该说view.remove(message)还是view.remove(index)?视图不应该尝试再次删除该消息,因为演示者已经这样做了。

滚动或添加等其他操作也是如此。如果收到新消息,演示者会将newMessages添加到allMessages,然后必须更新视图。理想情况下,演示者应该调用view.onMessagesReceived(List<Message> messages)而不是view.onMessageReceived(int newMessagesCount, int indexAddedAt)。第二种方法非常奇怪,而且根本没有冗长。但是由于列表正在共享,因此视图只需要调用notifyItemInserted,因此只需要了解计数和索引。

处理此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

正如Amir建议的那样,一种方法是从适配器公开一个方法来更新数据,然后调用notifyDataSetChanged。我真的不想使用这种方法,因为当我只想在适配器中添加/更新消息时,它会不必要地刷新整个数据集。

另一种方法是在视图中公开方法addNewMessages(int count, int index),以便适配器知道要通知插入/更新的索引,我再次不想使用,因为那时API似乎很奇怪因为addNewMessages实际上应该传递新消息列表而不是索引和计数。

我使用的解决方案是将整个更新后的列表从Presenter传递到View,最终将其传递给AdapterAdapter然后使用DiffUtil计算旧列表与新列表之间的差异,并且仅调用notifyItemInserted / notifyItemChanged方法而不是notifyDataSetChanged每个方法时间。

这有帮助,因为现在API看起来像这样:

ChatPresenter {
    interface View {
    ...
    void updateMessages(List<Message> messages);
}

Activity implements ChatPresenter.View {
    ...
    @Override
    void updateMessages(List<Message> messages) {
        chatsAdapter.update(messages);
    }
}

ChatsAdapter {
    ...
    public update(List<Message> messages) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ChatMessageDiffCallback(this.messages, updatedMessages));

        this.messages = updatedMessages;
        diffResult.dispatchUpdatesTo(this);
    }
}

答案 1 :(得分:0)

最佳做法是从视图实现更新适配器列表,但此任务的功能应该在视图接口上并在视图实现中实现(例如片段或活动)

首先向您的适配器添加一个方法,如下所示

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfStackOverflow.MyDragDrop
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        ViewModel vm = new ViewModel();
        public Window1()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

        #region WeekDay
            private void WeekDay_DragEnter(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.Text))
                    e.Effects = DragDropEffects.Copy;
            }
            private void WeekDay_Drop(object sender, DragEventArgs e)
            {
                ((TextBlock)sender).DataContext = e.Data.GetData(e.Data.GetFormats()[0]);
            }
            private void WeekDay_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                (sender as TextBlock).DataContext = null;
            }
        #endregion

        #region Teacher
            private void Teacher_LeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                TextBlock tb = (TextBlock)sender;
                DragDrop.DoDragDrop(tb, tb.DataContext, DragDropEffects.Copy | DragDropEffects.Move);
            }
            private void Teacher_DragEnter(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.Serializable))
                    e.Effects = DragDropEffects.Copy;
            }
        #endregion            
    }

    public class ViewModel : INotifyPropertyChanged
    {
        ObservableCollection<AppointmentRecord> _records = new ObservableCollection<AppointmentRecord>();
        public ObservableCollection<AppointmentRecord> AppointmentData { get { return _records; } }

        ObservableCollection<TeacherRecord> _teacherRecords = new ObservableCollection<TeacherRecord>();
        public ObservableCollection<TeacherRecord> TeacherData { get { return _teacherRecords; } }

        public ViewModel()
        {
            TeacherRecord trecord1 = new TeacherRecord() { Name = "A" };
            TeacherRecord trecord2 = new TeacherRecord() { Name = "B" };
            TeacherRecord trecord3 = new TeacherRecord() { Name = "C" };
            TeacherData.Add(trecord1);
            TeacherData.Add(trecord2);
            TeacherData.Add(trecord3);

            AppointmentRecord record1 = new AppointmentRecord() { Workshop = "WS-1", Mon = TeacherData.FirstOrDefault((t) => { return t.Name == "A"; }), Tue = null };
            AppointmentRecord record2 = new AppointmentRecord() { Workshop = "WS-2", Mon = null, Tue = TeacherData.FirstOrDefault((t) => { return t.Name == "C"; }) };
            AppointmentRecord record3 = new AppointmentRecord() { Workshop = "WS-3", Mon = null, Tue = null, Wed = TeacherData.FirstOrDefault((t) => { return t.Name == "C"; }) };            
            AppointmentData.Add(record1);            
            AppointmentData.Add(record2);
            AppointmentData.Add(record3);
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public void OnPropertyChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }    

    public class TeacherRecord
    {
        public string Name { get; set; }
    }

    public class AppointmentRecord : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public void OnPropertyChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }

        string _workshop;
        public string Workshop
        {
            get { return _workshop; }
            set
            {
                if (_workshop != value)
                {
                    _workshop = value;
                    OnPropertyChanged("Workshop");
                }
            }
        }

        TeacherRecord _mon;
        public TeacherRecord Mon
        {
            get { return _mon; }
            set
            {
                if (_mon != value)
                {
                    _mon = value;
                    OnPropertyChanged("Mon");
                }
            }
        }

        TeacherRecord _tue;
        public TeacherRecord Tue
        {
            get { return _tue; }
            set
            {
                if (_tue != value)
                {
                    _tue = value;
                    OnPropertyChanged("Tue");
                }
            }
        }

        TeacherRecord _wed;
        public TeacherRecord Wed
        {
            get { return _wed; }
            set
            {
                if (_wed != value)
                {
                    _wed = value;
                    OnPropertyChanged("Wed");
                }
            }
        }

        TeacherRecord _thu;
        public TeacherRecord Thu
        {
            get { return _thu; }
            set
            {
                if (_thu != value)
                {
                    _thu = value;
                    OnPropertyChanged("Thu");
                }
            }
        }

        TeacherRecord _fri;
        public TeacherRecord Fri
        {
            get { return _fri; }
            set
            {
                if (_fri != value)
                {
                    _fri = value;
                    OnPropertyChanged("Fri");
                }
            }
        }
    }
}

然后在您的视图界面中添加一个方法来更新适配器列表,如下所示

public void updateItemsList(ItemsList itemsList)
{
   //update the list of your items assume your items list is named "mItemsList"
   this.mItemsList = itemsList;
   notifyDataSetChanged();
}

然后在你的视图实现(片段或活动)中添加:

public void updateAdapterList(ItemsList itemsList);

现在,无论何时有类型为view interface的对象,都可以访问此方法(updateAdapterList())。