Wyjątek modyfikacji współbieżnej: dodawanie do ArrayList
Problem występuje w
Element element = it.next();
I ten kod, który zawiera ten wiersz, jest wewnątrz OnTouchEvent
for (Iterator<Element> it = mElements.iterator(); it.hasNext();){
Element element = it.next();
if(touchX > element.mX && touchX < element.mX + element.mBitmap.getWidth() && touchY > element.mY
&& touchY < element.mY + element.mBitmap.getHeight()) {
//irrelevant stuff..
if(element.cFlag){
mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
element.cFlag = false;
}
}
}
Wszystko to jest wewnątrz synchronized(mElements)
, Gdzie mElements
jest ArrayList<Element>
Kiedy dotknę Element
, może aktywować cFlag
, co utworzy kolejną Element
o różnych właściwościach, która spadnie z ekranu i zniszczy się w mniej niż sekundę. To mój sposób na tworzenie efektów cząsteczkowych. Możemy nazwać tę "cząstkę" crack
, podobnie jak parametr String w konstruktor.
Element
. Teraz mam dwa Elements
na ekranie w tym samym czasie, i jeśli dotknę najnowszego Element
, działa dobrze i uruchamia cząstki.
Jednak, jeśli dotknę i aktywuję cFlag
na starszym Element
, to daje mi wyjątek.
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): FATAL EXCEPTION: main
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): java.util.ConcurrentModificationException
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.Juggle2.Panel.onTouchEvent(Panel.java:823)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.View.dispatchTouchEvent(View.java:3766)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1767)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1119)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.app.Activity.dispatchTouchEvent(Activity.java:2086)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1751)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.view.ViewRoot.handleMessage(ViewRoot.java:1785)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.os.Handler.dispatchMessage(Handler.java:99)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.os.Looper.loop(Looper.java:123)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at android.app.ActivityThread.main(ActivityThread.java:4627)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.lang.reflect.Method.invokeNative(Native Method)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at java.lang.reflect.Method.invoke(Method.java:521)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:651)
07-28 15:36:59.815: ERROR/AndroidRuntime(4026): at dalvik.system.NativeStart.main(Native Method)
Jak mogę to zrobić?
7 answers
ConcurrentModificationException występuje podczas modyfikowania listy (poprzez dodawanie lub usuwanie elementów) podczas przechodzenia listy za pomocą Iterator
.
Try
List<Element> thingsToBeAdd = new ArrayList<Element>();
for(Iterator<Element> it = mElements.iterator(); it.hasNext();) {
Element element = it.next();
if(...) {
//irrelevant stuff..
if(element.cFlag){
// mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
thingsToBeAdd.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
element.cFlag = false;
}
}
}
mElements.addAll(thingsToBeAdd );
Należy również rozważyć enhanced dla każdej pętli, jak zasugerował Jon.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-28 22:02:29
Normalnie używam czegoś takiego:
for (Element element : new ArrayList<Element>(mElements)) {
...
}
Szybko, czysto i bez błędów
Inną opcją jest użycie CopyOnWriteArrayList
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-20 09:44:34
Nie możesz dodawać wpisu do kolekcji, gdy nad nią pracujesz.
Jedną z opcji jest utworzenie nowego List<Element>
dla nowych wpisów podczas iteracji mElements
, a następnie dodanie wszystkich nowych do mElement
(mElements.addAll(newElements)
). Oczywiście oznacza to, że nie wykonasz ciała pętli dla tych nowych elementów - czy to problem?
W tym samym czasie, polecam, aby zaktualizować swój kod, aby używać enhanced for loop :
for (Element element : mElements) {
...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-28 21:56:49
Pętla indeksowana for powinna również działać.
for (int i = 0; i < collection.size(); i++)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-28 13:01:54
Dodanie z listy w tym przypadku prowadzi do CME, żadna ilość synchronized
nie pozwoli Ci tego uniknąć. Zamiast tego rozważ dodanie za pomocą iteratora...
for(ListIterator<Element> it = mElements.listIterator(); it.hasNext();){
Element element = it.next();
if(touchX > element.mX && touchX < element.mX + element.mBitmap.getWidth() && touchY > element.mY
&& touchY < element.mY + element.mBitmap.getHeight()) {
//irrelevant stuff..
if(element.cFlag){
// mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
it.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
element.cFlag = false;
}
}
}
Również myślę, że to trochęśliskie aby stwierdzić jak...
...Problem występuje w
Element element = it.next();
Ze względu na precyzję należy pamiętać, że powyższe nie jest gwarantowane.
Dokumentacja API wskazuje, że to ...zachowanie nie może być zagwarantowane tak jak jest, ogólnie rzecz biorąc, niemożliwe jest dokonanie jakichkolwiek twardych gwarancji w obecności niezsynchronizowanej jednoczesnej modyfikacji. Operacje bezawaryjne rzucają ConcurrentModificationException na podstawie najlepszego wysiłku...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-29 00:17:16
Używanie iteratorów rozwiązuje również problemy ze współbieżnością, takie jak:
Iterator<Object> it = iterator.next().iterator();
while (it.hasNext()) {
it.remove();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-24 04:17:10
Cóż, próbowałem wszystkich aspektów w moim przypadku, w którym iterację w adapterze listy, ale z powodu uderzania raz po raz pokazałem mi wiadomość o wyjątku wyrzucany . Próbowałem wrzucić listę do
= (CopyOnWriteArraylist<MyClass>)mylist.value;
Ale to również rzuciło mi wyjątek od CouldNotCastException, (i w końcu zastanowiłem się nad tym, dlaczego używają lub zapewniają nam facality castingu).
Użyłem nawet tzw Synchronized Block zbyt, ale nawet to nie działa lub mógłbym mieć używałem go w niewłaściwy sposób.
Więc to wszystko, kiedy w końcu użyłem #all of time # techniki obsługi wyjątku w try catch block, I to działało Więc wpisz swój kod w
try{
//block
}catch(ConcurrentModificationException){
//thus handling my code over here
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-21 06:53:29