Troubleshooting: ConcurrentModificationException when accessing MutableLiveData Object in Android

Advertisements

java.util.ConcurrentModificationException happened in MutableLiveData Object proxy design pattern

In android I have Class that named Exam , Exam Have a List of Question and each Question have a List of Answer , So I created ModelView Like :

private final MutableLiveData<Exam> liveExam;
...
    public MutableLiveData<Exam> getExam() {
        return liveExam;
    }
...
    public void updateQuestion(int nextOrPrevious) throws Exception {
        int indexOfQuestion = questionPosition.getValue() + nextOrPrevious;
        if (indexOfQuestion >= 0 && (exam.getQuestions().size() >= (indexOfQuestion))) {
            mlQuestionText.postValue(liveExam.getValue().getQuestions().get(indexOfQuestion).getText());
            questionPosition.postValue(indexOfQuestion);
            mlExamQuestionNumber.postValue(TextUtil.toPersian(String.format(formattedQuestionNumberAndEndNumber, liveExam.getValue().getQuestions().get(indexOfQuestion).getIndex(), exam.getQuestions().size())));
        } else {
            throw new Exception("No more Question here");
        }
    }

everything work fine , but when I call :questionViewModel.getQuestionPosition().getValue().getQuestions()
.get(questionPosition).getAnswers()
if update answer like blow :

Iterator<Answer> iterator = exam.getQuestions().get(questionPosition)
.getAnswers().iterator();

while (iterator.hasNext()) {
         Answer answer = iterator.next();
answer.setAnswer(answer.getId() == checkedId);
exam.getQuestions().get(questionPosition).getAnswers().set(indexAnswer, answer);
      indexAnswer++;
                    }
                        questionViewModel.getExam().postValue(exam);
                      try {
                      questionViewModel.updateQuestion(1);
                         } catch (Exception e) {
                     e.printStackTrace();
                     }
       onUpdateQuestion();

I got an error for ConcurrentModificationException.

full print:

 java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at ir.mehritco.megnatis.cattell.ui.question.QuestionFragment$4.onCheckedChanged(QuestionFragment.java:185)                                                                      at android.widget.RadioGroup.setCheckedId(RadioGroup.java:200)
at android.widget.RadioGroup.access$600(RadioGroup.java:62)
at android.widget.RadioGroup$CheckedStateTracker.onCheckedChanged(RadioGroup.java:385)
at android.widget.CompoundButton.setChecked(CompoundButton.java:221)
at android.widget.CompoundButton.toggle(CompoundButton.java:137)
at android.widget.RadioButton.toggle(RadioButton.java:77)
at android.widget.CompoundButton.performClick(CompoundButton.java:142)
at android.view.View.performClickInternal(View.java:7425)
at android.view.View.access$3600(View.java:810)
at android.view.View$PerformClick.run(View.java:28305)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

what happened here? and way I got this error?
I try some ways like store exam value in another Object and than post exam value or getQuestion from modelView as MutableLiveData but result as same!
My goal is :
Store answer(data) into answer(object)
so for this I need goto exam goto question list get question goto answer list get answer and updated

>Solution :

You’re not supposed to modify collections while iterating except via the iterator. You can use ListIterator to do that:

ListIterator<Answer> iterator = exam.getQuestions()
        .get(questionPosition).getAnswers().listIterator();

while (iterator.hasNext()) {
    Answer answer = iterator.next();
    answer.setAnswer(answer.getId() == checkedId);
    iterator.set(answer);
}

Or you could use an indexed loop instead of an iterator.

But in this case there’s no point in calling set() at all, because you’re not updating the answer reference, just the state of the object already in the list. So you can simplify this to a simple for loop or use forEach():

exam.getQuestions()
        .get(questionPosition)
        .getAnswers()
        .forEach(a -> a.setAnswer(a.getId() == checkedId));

Leave a Reply Cancel reply