在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
,因此只需要了解计数和索引。
处理此问题的最佳方法是什么?
答案 0 :(得分:2)
正如Amir建议的那样,一种方法是从适配器公开一个方法来更新数据,然后调用notifyDataSetChanged
。我真的不想使用这种方法,因为当我只想在适配器中添加/更新消息时,它会不必要地刷新整个数据集。
另一种方法是在视图中公开方法addNewMessages(int count, int index)
,以便适配器知道要通知插入/更新的索引,我再次不想使用,因为那时API似乎很奇怪因为addNewMessages
实际上应该传递新消息列表而不是索引和计数。
我使用的解决方案是将整个更新后的列表从Presenter
传递到View
,最终将其传递给Adapter
。 Adapter
然后使用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())。