Java 如何修复使用DiffUtil向ListUpdateCallback发送更新时出现的错误位置

Java 如何修复使用DiffUtil向ListUpdateCallback发送更新时出现的错误位置,java,android,android-diffutils,Java,Android,Android Diffutils,我有一个Android应用程序,用户可以同时使用EditText修改多个String项,因此我需要找出哪些内容发生了更改,以便将更改通知服务器(创建新项、更新现有项或删除后者),这就是为什么我使用DiffUtil和ListUpdateCallback来实现这一点。如果旧列表的大小为2项,则会出现问题;我删除了索引0处的项目,然后在列表的末尾添加了3个项目,我得到了一个回调,返回到onInserted,位置参数不正确,这导致IndexOutOfBoundsException,(这是删除旧列表中除最

我有一个Android应用程序,用户可以同时使用
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
not
I 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());
}