Java 如何修复使用DiffUtil向ListUpdateCallback发送更新时出现的错误位置
我有一个Android应用程序,用户可以同时使用Java 如何修复使用DiffUtil向ListUpdateCallback发送更新时出现的错误位置,java,android,android-diffutils,Java,Android,Android Diffutils,我有一个Android应用程序,用户可以同时使用EditText修改多个String项,因此我需要找出哪些内容发生了更改,以便将更改通知服务器(创建新项、更新现有项或删除后者),这就是为什么我使用DiffUtil和ListUpdateCallback来实现这一点。如果旧列表的大小为2项,则会出现问题;我删除了索引0处的项目,然后在列表的末尾添加了3个项目,我得到了一个回调,返回到onInserted,位置参数不正确,这导致IndexOutOfBoundsException,(这是删除旧列表中除最
EditText
修改多个String
项,因此我需要找出哪些内容发生了更改,以便将更改通知服务器(创建新项、更新现有项或删除后者),这就是为什么我使用DiffUtil
和ListUpdateCallback
来实现这一点。如果旧列表的大小为2项,则会出现问题;我删除了索引0处的项目,然后在列表的末尾添加了3个项目,我得到了一个回调,返回到onInserted
,位置参数不正确,这导致IndexOutOfBoundsException
,(这是删除旧列表中除最后一个项目之外的任何项目的行为)请看一下
我尝试了以下代码,并对新列表进行了其他更改,如在索引1处删除,然后在列表末尾添加3项,效果很好
我正在使用的数组的类型为Answer,它是一个类:
public class Answer {
private String id;
private String questionId;
private String text;
private Integer count;
}
请注意,如果两个项目相同,则可通过id识别两个不同的对象;然后可以通过文本识别内容
DiffUtil.Callback
public class AnswersDiffCallback extends DiffUtil.Callback {
List<Answer> newAnswers;
List<Answer> oldAnswers;
public AnswersDiffCallback(List<Answer> newAnswers, List<Answer> oldAnswers) {
this.newAnswers = newAnswers;
this.oldAnswers = oldAnswers;
}
@Override
public int getOldListSize() {
return oldAnswers == null ? 0 : oldAnswers.size();
}
@Override
public int getNewListSize() {
return newAnswers == null ? 0 : newAnswers.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
Answer oldAnswer = oldAnswers.get(oldItemPosition);
Answer newAnswer = newAnswers.get(newItemPosition);
return Objects.equals(oldAnswer.getId(), newAnswer.getId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Answer oldAnswer = oldAnswers.get(oldItemPosition);
Answer newAnswer = newAnswers.get(newItemPosition);
return Objects.equals(oldAnswer.getText(), newAnswer.getText());
}
}
这一行的问题在于:
2019-06-19 16:35:19.550 24515-24515/com.example.myApp D/AdminQuestionsFragment: onInserted: (position, count) = (2, 3)
为什么位置不是1
更新1
如果我有2个项目的旧列表,并且我删除了索引1中的项目,然后在列表末尾添加了3个项目,则日志如下:
2019-06-19 18:25:24.368 28118-28118/com.example.myApp D/AdminQuestionsFragment: answers: oldAnswers = [{"count":0,"id":"5d09a1236969e249cca42e96","questionId":"5d09a1236969e249cca42e95","text":"old answer 0"},{"count":0,"id":"5d09a1236969e249cca42e97","questionId":"5d09a1236969e249cca42e95","text":"old answer 1"}]
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: answers: newAnswers = [{"count":0,"id":"5d09a1236969e249cca42e96","questionId":"5d09a1236969e249cca42e95","text":"old answer 0"},{"text":"new answer 0"},{"text":"new answer 1"},{"text":"new answer 2"}]
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: onRemoved: (position, count) = (1, 1)
2019-06-19 18:25:24.371 28118-28118/com.example.myApp D/AdminQuestionsFragment: onRemoved: (oldAnswer.id, oldAnswer.text) = (5d09a1236969e249cca42e97, old answer 1)
2019-06-19 18:25:24.371 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: (position, count) = (1, 3)
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 0
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 1
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 2
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
for(int i=position;i
此循环肯定会抛出IndexOutOfBoundError
<代码>计数是已添加的项目数。position
是新项目的位置。当你做position+count
的时候,在某一点上肯定会超过你列表的大小。这就是错误
如果旧列表的大小为2项,则会出现问题;我删除了索引0处的项目,然后在列表末尾添加了3个项目
在删除新项目之后和添加新项目之前,是否调用dispatchUpdates
我认为首先是计算插入的项目,然后是删除的项目,因此在onInserted
中的位置是2
如果需要批量更新,可以将
ListUpdateCallback
包装在BatchingListUpdateCallback
中。如果位置正确,为什么会抛出IndexOutOfBoundsException
?例如,如果我在列表的开头插入了2个项目,那么位置应该是0,计数应该是2,那么循环将使用I
:0,1
的这些值运行,这些值不应该引发任何异常。在删除和添加新项目之前,我没有调用dispatchUpdates
,我只是在新列表完全修改之后才调用它!请看更新的帖子,我已经发布了一个很好的例子!在您的更新1
之后,出现了什么问题?这似乎和预期的一样。您说您首先删除了位置0处的项目(最初有2个项目),然后在最后添加了3个项目。此时,共有4个项目。现在,count是3,position是2=>count+position是5,大于列表(4)的大小。由于您在一次分派中执行多个更改,因此有可能DiffUtil
首先调用onInserted
,然后调用onRemoved
。我不知道确切的算法为什么或者如何工作。是的,但是为什么位置是2,我发布的另一个例子是,我删除了索引1处的项目,然后得到了一个回调onInserted
,位置正确!请注意,我使用的是I
notI DiffUtil使用的是Myers的diff算法——这很复杂,所以我不知道,但根据不同,它可能会按顺序调用不同的方法。
2019-06-19 16:35:19.550 24515-24515/com.example.myApp D/AdminQuestionsFragment: onInserted: (position, count) = (2, 3)
2019-06-19 18:25:24.368 28118-28118/com.example.myApp D/AdminQuestionsFragment: answers: oldAnswers = [{"count":0,"id":"5d09a1236969e249cca42e96","questionId":"5d09a1236969e249cca42e95","text":"old answer 0"},{"count":0,"id":"5d09a1236969e249cca42e97","questionId":"5d09a1236969e249cca42e95","text":"old answer 1"}]
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: answers: newAnswers = [{"count":0,"id":"5d09a1236969e249cca42e96","questionId":"5d09a1236969e249cca42e95","text":"old answer 0"},{"text":"new answer 0"},{"text":"new answer 1"},{"text":"new answer 2"}]
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
2019-06-19 18:25:24.370 28118-28118/com.example.myApp D/AdminQuestionsFragment: onRemoved: (position, count) = (1, 1)
2019-06-19 18:25:24.371 28118-28118/com.example.myApp D/AdminQuestionsFragment: onRemoved: (oldAnswer.id, oldAnswer.text) = (5d09a1236969e249cca42e97, old answer 1)
2019-06-19 18:25:24.371 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: (position, count) = (1, 3)
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 0
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 1
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: onInserted: newAnswer.text = new answer 2
2019-06-19 18:25:24.372 28118-28118/com.example.myApp D/AdminQuestionsFragment: -----------------------------------------------------------------------------
for (int i = position; i < position + count; i++) {
Log.d(TAG, "onInserted: newAnswer.text = " + newAnswers.get(i).getText());
}