Java Question WrappedObject becomes Object

warwound

Expert
Licensed User
Longtime User
WrappedObject becomes Object

My new MapView library is causing a problem...

I created some example code to show how to add Marker objects to a MarkersOverlay object.

It creates 2 Markers, creates a List and Initializes the List passing the 2 Markers to the List Initialize2 method as an Array:

B4X:
   '   initialize the MarkersOverlay and add it to the MapView
   MarkersOverlay1.Initialize(MapView1, "")
   MapView1.AddOverlay(MarkersOverlay1)
   
   '   create and initialize 2 Markers
   '   for Marker1 i'll use a custom icon
   Dim Icon As BitmapDrawable
   Icon.Initialize(LoadBitmap(File.DirAssets, "my_icon.png"))
   
   Dim Marker1 As Marker
   Marker1.Initialize("Home sweet home", "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 52.75610, 0.39748, Icon)
   
   '   Marker2 will display the default OSMDroid icon
   '   the default icon is used if Null is passed as the Icon parameter
   Dim Marker2 As Marker
   Marker2.Initialize("Elsewhere", "Downham Market", 52.60801, 0.39047, Null)
   
   '   create a List and initialize it with the 2 Markers
   Dim Markers As List
   Markers.Initialize2(Array As Marker(Marker1, Marker2))
   
   '   add the List of Markers to the MarkersOverlay
   MarkersOverlay1.AddMarkers(Markers)

Works perfectly.

Bluedude is trying to create Markers in a loop and add them to the MarkersOverlay but instead of using List method Initialize2 to add an array of Markers to the List he is adding them 1 at a time using the List method Add.
The list and all other objects are properly Initialized:

B4X:
   ovlLocation.Initialize(mapDisp, "ovlLocation")
   mapDisp.AddOverlay(ovlLocation)
   
   'for Marker1 i'll use a custom icon
   Dim Icon As BitmapDrawable
   Icon.Initialize(LoadBitmap(File.DirAssets, "my_icon.png"))
   
   Dim Markers As List
   Markers.Initialize

   For i=0 To 10
       Dim Marker1 As Marker
       Marker1.Initialize("Home sweet home", "bla", 52.75610, 0.39748, Icon)
       Markers.add(Marker1)
   Next

   'add markers to overlay
   ovlMarkers.AddMarkers(Markers)

The Activity force closes with a ClassCastException:

** Activity (main) Create, isFirst = true **
Class=org.osmdroid.views.overlay.OverlayItem
main_activity_create (java line: 257)

java.lang.ClassCastException: org.osmdroid.views.overlay.OverlayItem
at uk.co.martinpearman.b4a.osmdroid.views.overlays.B4AItemizedIconOverlayWrapper.AddMarkers(B4AItemizedIconOverlayWrapper.java:90)
at uk.co.martinpearman.b4a.mapviewtutorial.main._activity_create(main.java:257)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at uk.co.martinpearman.b4a.mapviewtutorial.main.afterFirstLayout(main.java:84)
at uk.co.martinpearman.b4a.mapviewtutorial.main.access$100(main.java:16)
at uk.co.martinpearman.b4a.mapviewtutorial.main$WaitForLayout.run(main.java:72)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3835)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
java.lang.ClassCastException: org.osmdroid.views.overlay.OverlayItem

My library AddMarkers method is:

B4X:
public void AddMarkers(anywheresoftware.b4a.objects.collections.List Markers) {
      List<OverlayItem> overlayItems = new ArrayList<OverlayItem>();
      OverlayItemWrapper overlayItemWrapper;
      int count = Markers.getSize();
      while (count-- > 0) {

         Log.d("B4A", "Class=" + Markers.Get(count).getClass().getName());

         overlayItemWrapper = (OverlayItemWrapper) Markers.Get(count); // ClassCastException here
         overlayItems.add(overlayItemWrapper.getObject());
      }
      getObject().addItems(overlayItems);
   }

Marker is the IDE ShortName for a uk.co.martinpearman.b4a.osmdroid.views.overlays.OverlayItemWrapper - which wraps org.osmdroid.views.overlay.OverlayItem.
That is AnOverlayItemWrapper.getObject() returns an AnOverlayItem.

With the working code my Log statement produces:

Class=uk.co.martinpearman.b4a.osmdroid.views.overlays.OverlayItemWrapper

All is as expected, but the non-working code Logs:

Class=org.osmdroid.views.overlay.OverlayItem

The OverlayItemWrapper has become an OverlayItem and causes the ClassCastException.

Why does this happen - why does the method used to add a Marker object to a List change the class of that Marker object?

I can upload the working and non-working project if anyone want's to take a look.

Thanks.

Martin.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Whenever an ObjectWrapper is passed to a method that expects an Object (or any other type that is not exact ObjectWrapper), the ObjectWrapper is unwrapped. This is a powerful feature of ObjectWrapper.

For example Activity.AddView expects a View as the first parameter. Without this feature you will not be able to pass any ViewWrapper to this method.

The best solution is to accept the native object and not the wrapped object.
The B4A code should have been:
B4X:
Markers.Initialize2(Array As Object(Marker1, Marker2))

However as you probably don't want to break existing code you may prefer to check the type at runtime:
B4X:
 while (count-- > 0) {
            OverlayItem oi;
            Object o =  Markers.Get(count);
            if (o instanceof OverlayItemWrapper)
               oi = ((OverlayItemWrapper)o).getObject();
            else
               oi = (OverlayItem)o;

            ...
        }
 

warwound

Expert
Licensed User
Longtime User
Right - i have some updating to do then.

I have other methods such as:

B4X:
public void SetCenter2(LocationWrapper aLocation) {
      getObject().getController().setCenter(new GeoPoint(aLocation.getObject()));
   }

Where presumably i can change the LocationWrapper for a Location and if a LocationWrapper is passed to the method then the method will receive a Location?

All my non-View classes extend AbsObjectWrapper, and MapView is the only class that extends ViewWrapper by the way.

Martin.
 
Top