从onLocationMethod获取ConcurrentModificationException

时间:2016-11-10 07:16:40

标签: java android multithreading arraylist concurrentmodification

我正在尝试按照服务中的逻辑更新ArrayList位置,通过Runnable在后台线程中运行。我已编辑代码以仅显示相关代码。我得到了ConcurrentModificationException

public static ArrayList<Location> locationPoints;


@Override
public void onLocationChanged(final Location location) {
    //Log.i(TAG, "onLocationChanged: " + location);
    Log.i(TAG, "onLocationChanged: " + locationPoints.size());

    ArrayList<Location> alnew= locationPoints;

    if(!locationPoints.isEmpty()){
        for(Location l:alnew){
            if(location.distanceTo(l)<=200.0f){
                locationPoints.add(l);
            }else{
                locationPoints.add(location);
            }
        }
    }else{
        locationPoints.add(location);
    }

    sendLocationsToActivity(locationPoints);
}

我希望位置对象一个接一个地移动,但我看到位置对象呈指数级增长。

登录onLocationChanged的结果如下。例外情况来自ArrayList方法,但即使使用了此处给出的所有补救措施,我也无法找到解决方案。

  

onLocationChanged:0
  onLocationChanged:1
  onLocationChanged:2
  onLocationChanged:4
  onLocationChanged:8
  onLocationChanged:16
  onLocationChanged:32

但是,如果我从ArrayList删除所有onLocationChanged逻辑,只需将位置对象添加到ArrayList,结果就是我想要的方式

  

onLocationChanged:0
  onLocationChanged:1
  onLocationChanged:2
  onLocationChanged:3
  onLocationChanged:4
  onLocationChanged:5

堆栈跟踪:

FATAL EXCEPTION: main
Process: com.amreen.test, PID: 27053
Theme: themes:{default=overlay:com.resurrectionremix.pitchblack, fontPkg:com.resurrectionremix.pitchblack, com.android.systemui=overlay:com.resurrectionremix.pitchblack, com.android.systemui.headers=overlay:com.resurrectionremix.pitchblack, com.android.systemui.navbar=overlay:com.resurrectionremix.pitchblack}
java.util.ConcurrentModificationException
    at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
    at com.amreen.test.MyLocationService.onLocationChanged(MyLocationService.java:146)
    at com.google.android.gms.location.internal.zzk$zzb.handleMessage(Unknown Source)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5458)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

2 个答案:

答案 0 :(得分:2)

在使用Iterator遍历列表时修改列表(添加或删除元素)时发生ConcurrentModificationException。 for-each循环只不过是java.util.Iterator的语法糖。所以这里的逻辑就像:

for() {
     if(someCondition) {
         locationPoints.add(sth);
   }
}

而不是你可以尝试像:

for() {
         if(someCondition) {
             someOtherArrayList.add(sth);
       }
    }

一旦退出循环,那么:

locationPoints.addAll(someOtherArrayList);

答案 1 :(得分:1)

这是因为ArrayList的实现,请参考文档 ArrayList document

  

此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。

您首先获得迭代器,然后使用它进行添加。 示例

  

Iterator<Location> iter = locationPoints.iterator(); while (iter.hasNext()) { Location location = iter.next(); if(location.distanceTo(l)<=200.0f){ iter.add(l); }else{ iter.add(location); } }