Search code examples
javaandroidandroid-asynctaskconcurrentmodification

FATAL EXCEPTION: AsyncTask caused by ConcurrentModificationException


I am new to Android and developing in general so any help is appreciated. Most of the questions (and answers) about a "FATAL EXCEPTION in an AsyncTask" were NullpointerExceptions so I think I am allowed to ask.

I use this Midi-driver https://github.com/kshoji/USB-MIDI-Driver to get notes from an external keyboard. I add received notes to an array, so that I have sequence of played notes. Then I use an AsyncTask to match parts of my input to a given list of notes. The two methods "calculate matrix" and "sync" are basically copied (simplified) from a thesis about synchronizing musical data.

so my Activity does this:

private void syncInput() {
    if(syncTask.getStatus() != AsyncTask.Status.RUNNING){
        syncTask = new SynchronisationTask(this, synchronizer);
        syncTask.execute();
    }
}

my AsyncTask does this:

public SynchronisationTask(ShowNotesActivity sna, Synchronizer s){
    this.showNotesActivity = sna;
    this.synchronizer = s;
}
@Override
protected Integer doInBackground(Mat... params) {
    return synchronizer.getPosition();
}

and my synchronizer this:

public int getPosition() {
...
    if(input.size() < 10){
        length = input.size();
    }
    currentPart = partNotes.subList(0, 11);
    currentInput = input.subList(input.size() - length, input.size());

    if(currentPart.size() > 0 && currentInput.size() > 0){
        cost = new int[currentPart.size()][currentInput.size()];
        calculateMatrix();
        sync();
    }
    //not yet sure what I want to return so its 0
    return 0;
}

private void sync() {
    int i = currentPart.size()-1;
    int j = currentInput.size()-1;
    List<Pair<Integer,Integer>> pmMatch = new ArrayList<>();
    while(i > 0 && j > 0){
        if(cost[i][j] == cost[i][j-1]){
            j--;
        }else{
            if(cost[i][j] == cost[i-1][j]){
                i--;
            } else{
                pmMatch.add(Pair.create(i,j));
                i--;
                j--;
            }
        }
    }
    int max = 1;
    for(Pair p : pmMatch){
        if((int)p.first > max)
            max = (int)p.first;
    }
    lastNote = max;
    lastMatch = pmMatch.size();
    match++;
}

private void calculateMatrix(){
    int p = currentPart.size();
    int m = currentInput.size();

    int c = fivePointTwo();
    for(int i = 0; i < p; i++){
        cost[i][0] = c;
    }
    for(int j = 1; j < m; j++){
        cost[0][j] = c;
    }
    for(int i = 1; i < p; i++){
        for (int j = 1; j < m; j++) {
            int d = fivePointFour(currentPart.get(i), currentInput.get(j));
            if(cost[i-1][j-1] + d < Math.min(cost[i-1][j], cost[i][j-1])){
                cost[i][j] = cost[i-1][j-1] + d;
            }
            else if(cost[i-1][j] < cost[i][j-1]){
                cost[i][j] = cost[i-1][j];
            } else{
                cost[i][j] = cost[i][j-1];
            }
        }
    }
}

My app kept crashing at more or less random times and now I finally got some info... which I do not understand. I hope you can help me with this error:

06-08 01:30:18.149  26521-27123/ba.myapplication E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #3
Process: ba.myapplication, PID: 26521
java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:300)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
 Caused by: java.util.ConcurrentModificationException
        at java.util.AbstractList$SubAbstractList.size(AbstractList.java:360)
        at ba.myapplication.Synchronizer.sync(Synchronizer.java:89)

sync(Synchronizer.java:89) is the second line in the "sync" method: int j = currentInput.size()-1;


Solution

  • In getPosition() the code currentInput = input.subList(input.size() - length, input.size()); is causing the issue. Looks like you are modifying input list while getPosition() is working.

    From subList javadoc:

    The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

    You can either try to create a copy of input's sub list: currentInput = new ArrayList<>(input.subList(input.size() - length, input.size()));, or add synchronization to your code.