致命异常:由 ConcurrentModificationException 引起的 AsyncTask

FATAL EXCEPTION: AsyncTask caused by ConcurrentModificationException

我是 Android 的新手并且总体上正在开发中,因此非常感谢您的帮助。大多数关于 "FATAL EXCEPTION in an AsyncTask" 的问题(和答案)都是 NullpointerExceptions,所以我想我可以问。

我使用这个 Midi 驱动程序 https://github.com/kshoji/USB-MIDI-Driver 从外部键盘获取音符。我将收到的音符添加到一个数组中,这样我就有了演奏音符的顺序。然后我使用 AsyncTask 将我的部分输入与给定的笔记列表相匹配。 "calculate matrix"和"sync"这两个方法基本上是从一篇关于同步音乐数据的论文中复制(简化)而来的。

所以我的 Activity 这样做:

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

我的 AsyncTask 这样做:

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

我的同步器是这样的:

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];
            }
        }
    }
}

我的应用程序或多或少地随机崩溃,现在我终于得到了一些信息......我不明白。我希望你能帮我解决这个错误:

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.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.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)是"sync"方法中的第二行:int j = currentInput.size()-1;

getPosition() 中,代码 currentInput = input.subList(input.size() - length, input.size()); 导致了问题。看起来您正在修改 input 列表,而 getPosition() 正在工作。

来自 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.)

您可以尝试创建输入子列表的副本:currentInput = new ArrayList<>(input.subList(input.size() - length, input.size()));,或将同步添加到您的代码中。