Java Question Passing B4A List as ArrayList

warwound

Expert
Licensed User
Longtime User
I'm wrapping a 3rd party library, there is a native library method:

B4X:
//   native library method
public Road getRoad(ArrayList<GeoPoint> waypoints) {
    // method body here
}

Normally i'd create a wrapper method that accepts a B4A List or Array of GeoPoint objects, and within that wrapper method create a parameterized ArrayList<GeoPoint> to pass to the native library method.
(Working around the fact that a B4A List isn't parameterized).
But as an experiment i instead created a wrapper method that accepts a B4A List and passes that B4A List directly to the native method as the parameterized ArrayList<GeoPoint> parameter:

B4X:
//   B4A library method
public void GetRoad(ArrayList<GeoPoint> Waypoints) {
   //   here i call getObject().getRoad(Waypoints)
}

I tested it with this code:

B4X:
Dim WayPoints As List
WayPoints.Initialize
WayPoints.Add(OriginPoint)
WayPoints.Add(DestinationPoint)
OSRMRoadManager1.GetRoad(WayPoints)

It works as expected.
OriginPoint and DestinationPoint are GeoPointWrapper objects, the underlying GeoPoint objects are added to the List so WayPoints is an unparameterized ArrayList of GeoPoint objects.
I set a breakpoint and see:
WayPoints (ArrayList)[52752480,404300,0,52743566,402374,0]
The GeoPoint can use units of degrees or micro-degrees, the breakpoint shows units of micro-degrees.
Next i tried this:

B4X:
Dim WayPoints As List
WayPoints.Initialize
WayPoints.AddAll(Array As GeoPoint(OriginPoint, DestinationPoint))
OSRMRoadManager1.GetRoad(WayPoints)

The method no longer works, no exceptions are thrown but the method does nothing.
The breakpoint shows:
WayPoints (ArrayList)[52.752480,0.404300,0,52.743566,0.402374,0]
The breakpoint now shows units of degrees.
I then tried this:

B4X:
Dim WayPoints As List
WayPoints.Initialize2(Array As GeoPoint(OriginPoint, DestinationPoint))
OSRMRoadManager1.GetRoad(WayPoints)

The breakpoint shows WayPoints with units of degrees.
Calling GetRoad now throws an exception:

java.lang.ClassCastException: java.util.Arrays$ArrayList

Ignoring the breakpoint showing different units (degrees/micro-degrees) why does the B4A List have a different behaviour depending on how it is Initialized or how items are added to it?

Martin.
 

warwound

Expert
Licensed User
Longtime User
I added the code you suggested as well as a line to log the type of the Waypoints List:

B4X:
Dim Obj As Object
For Each Obj As Object In WayPoints
   Log(GetType(Obj))
Next
Log(GetType(WayPoints))

Here's the results:
  • B4X:
    Dim WayPoints As List
    WayPoints.Initialize
    WayPoints.Add(OriginPoint)
    WayPoints.Add(DestinationPoint)
    org.osmdroid.util.GeoPoint
    org.osmdroid.util.GeoPoint
    java.util.ArrayList
  • B4X:
    Dim WayPoints As List
    WayPoints.Initialize
    WayPoints.AddAll(Array As GeoPoint(OriginPoint, DestinationPoint))
    uk.co.martinpearman.b4a.osmdroid.util.wrappers.GeoPointWrapper
    uk.co.martinpearman.b4a.osmdroid.util.wrappers.GeoPointWrapper
    java.util.ArrayList
  • B4X:
    Dim WayPoints As List
    WayPoints.Initialize2(Array As GeoPoint(OriginPoint, DestinationPoint))
    uk.co.martinpearman.b4a.osmdroid.util.wrappers.GeoPointWrapper
    uk.co.martinpearman.b4a.osmdroid.util.wrappers.GeoPointWrapper
    java.util.Arrays$ArrayList
    main_getroutebutton_click (java line: 322)
    java.lang.ClassCastException: java.util.Arrays$ArrayList
    at uk.co.martinpearman.b4a.osmbonuspackexample.main._getroutebutton_click(main.java:322)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:165)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:153)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:149)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:55)
    at android.view.View.performClick(View.java:2506)
    at android.view.View$PerformClick.run(View.java:9112)
    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: java.util.Arrays$ArrayList

I was more or less expecting a problem with GeoPoint or GeoPointWrapper objects being added to the List depending on the method used to add them - i've had a similar problems a few times with the OSMDroid library with no bulletproof solution.
I could write code in the wrapper method to detect if GeoPoint or GeoPointWrapper objects have been passed to it (not very elegant) or i could change the method to accept an Array of GeoPoint objects and hope(!) that adding a GeoPoint to an Array will always add a GeoPoint and not 'sometimes' add a GeoPointWrapper depending the on the syntax used to construct the Array...

B4X:
Dim WayPoints() As GeoPoint=Array As GeoPoint(OriginPoint, DestinationPoint)
B4X:
Dim WayPoints(2) As GeoPoint
WayPoints(0)=OriginPoint
WayPoints(1)=DestinationPoint

These both log:

org.osmdroid.util.GeoPoint
org.osmdroid.util.GeoPoint
[Luk.co.martinpearman.b4a.osmdroid.util.wrappers.GeoPointWrapper;

So it looks an an Array is the way to go, that's a shame as a List is so much more flexible.

As for the ClassCastException, reading the documentation for the List Initialize2 method it states:

Initializes a list with the given values. This method should be used to convert arrays to lists.
Note that if you pass a list to this method then both objects will share the same list,
and if you pass an array the list will be of a fixed size. Meaning that you cannot later add or remove items.

So the List created with Initialize2 is actually an Array wrapper not an ArrayList wrapper - i think that makes sense.

Martin.
 
Last edited:

Firpas

Active Member
Licensed User
Longtime User
Hi to everybody;

A java question ....

How to parse a

anywheresoftware.b4a.objects.collections.List

to

java.util.ArrayList ???

Thanks in advance
 

DonManfred

Expert
Licensed User
Longtime User
You better create a NEW thread instead of pulling out an two year old one
 
Top