amiqat / osmdroid

Automatically exported from code.google.com/p/osmdroid
0 stars 0 forks source link

ItemizedOverlay synchronization on draw #365

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1. Create a list of a lot of OverlayItem (here it was 101)
2. Add the list to an ItemizedIconOverlay<OverlayItem> contained in the MapView.
3. Refresh view at the end or after adding each OverlayItem.

What is the expected output? What do you see instead?
Display of all items on map expected but following exception occurs:
08-24 09:34:09.965: ERROR/AndroidRuntime(1115): FATAL EXCEPTION: main
08-24 09:34:09.965: ERROR/AndroidRuntime(1115): 
java.lang.IndexOutOfBoundsException: Invalid index 92, size is 68
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
java.util.ArrayList.get(ArrayList.java:308)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
org.osmdroid.views.overlay.ItemizedOverlay.getItem(ItemizedOverlay.java:149)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
org.osmdroid.views.overlay.ItemizedOverlay.draw(ItemizedOverlay.java:116)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
org.osmdroid.views.overlay.OverlayManager.onDraw(OverlayManager.java:119)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
org.osmdroid.views.MapView.dispatchDraw(MapView.java:867)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.drawChild(ViewGroup.java:2582)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2189)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.drawChild(ViewGroup.java:2582)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2189)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.drawChild(ViewGroup.java:2582)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2189)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.drawChild(ViewGroup.java:2582)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2189)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.drawChild(ViewGroup.java:2582)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2189)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.View.draw(View.java:9282)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.widget.FrameLayout.draw(FrameLayout.java:419)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:192
3)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewRoot.draw(ViewRoot.java:1695)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewRoot.performTraversals(ViewRoot.java:1410)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.view.ViewRoot.handleMessage(ViewRoot.java:2040)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.os.Handler.dispatchMessage(Handler.java:99)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.os.Looper.loop(Looper.java:132)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
android.app.ActivityThread.main(ActivityThread.java:4135)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
java.lang.reflect.Method.invokeNative(Native Method)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
java.lang.reflect.Method.invoke(Method.java:491)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
08-24 09:34:09.965: ERROR/AndroidRuntime(1115):     at 
dalvik.system.NativeStart.main(Native Method)

What version of the product are you using? On what operating system?
Version 3.0.8 on Android 3.2

Additional informations:

  private MapView mapView;
  private ItemizedIconOverlay<OverlayItem> mapPoints;

...

mapView.getOverlays().add(mapPoints);

...add all overlay items in list

      this.mapPoints.addItem(myOverlayItem);

Proposed fix:
We have the exception because the list is not synchronized. It is accessed 
simultaneously in draw method and by the addItem, addItems, removeItem and 
removeAllItems methods.
The problem is solved by synchronizing all those methods.
Another solution (better in my opinion but I didn't test it) is to do the 
synchronization one step lower in ItemizedOverlay<Item> class on populate, 
getItem and draw methods.

Original issue reported on code.google.com by laurentg...@gmail.com on 24 Aug 2012 at 8:00

GoogleCodeExporter commented 8 years ago
The problem is that it calculates the size at line 112 and then loops, but in 
the meantime the size has changed.
It would probably be better to use an iterator and quit on 
ConcurrentModificationException.
Alternatively you could use .size() directly in the for loop, but it in that 
case it would still be using an index that doesn't quite make sense any more.

When you say "synchronizing all those methods" do you mean adding a 
synchronized keyword to the method declaration, or do you mean a synchronized 
block?

From what I hear from people cleverer than me is that you should avoid the Java 
native implementations like synchronized because Android has better 
implementations.

Original comment by neilboyd on 24 Aug 2012 at 11:25

GoogleCodeExporter commented 8 years ago
I ment adding a synchronized block but now that you say it, I think your 
proposed solution with the synchronize keyword on method declaration is cleaner.
I didn't know of this synchronisation mechanism in Android, I will investigate 
on it.

Original comment by laurentg...@gmail.com on 28 Aug 2012 at 10:19

GoogleCodeExporter commented 8 years ago
you can also use an asyncpost by doing like this 
do on the doinbackground the :
mapView.getOverlays().add(mapPoints);
and in the onPostexecute :
this.mapPoints.addItem(myOverlayItem);

Original comment by tamisier...@gmail.com on 13 Dec 2012 at 10:13

GoogleCodeExporter commented 8 years ago
This problem is not osmdroid related and appears to be fixed anyway.

Original comment by kurtzm...@gmail.com on 5 Mar 2013 at 6:19

GoogleCodeExporter commented 8 years ago
I am still getting this issue regularly. Exactly same procedure to reproduce it 
as Laurent.

Original comment by eenriquelopez@gmail.com on 2 Sep 2013 at 12:00