B4A Library OSMDroid - MapView for B4A

Here we have my latest library - OSMDroid provides a MapView for B4A.

More info on the original (native Android) OSMDroid project can be found here: osmdroid - OpenStreetMap-Tools for Android - Google Project Hosting.

Library reference is no longer included in this post due to limits on the number of characters allowed in a single post.

I have created some tutorials to show basic usage of the library and will update this thread with a link to them as soon as i have them all uploaded.

** Your attention is drawn to the included file Apache License Version 2.0.txt, which is a copy of the Apache License Version 2.0 under which the native Android OSMDroid library is released **

Martin.
 

Attachments

  • OSMDroid_3_0_8_v3.60.zip
    361.9 KB · Views: 4,212
Last edited:

warwound

Expert
Licensed User
Longtime User
I'm back and have been thinking about this...

I'll put a test project together - i suspect that the way that the Markers (which are OverlayItemWrappers) are added to the List is causing them to be cast to their native OverlayItem.

The working code adds the Markers as an Array:

B4X:
Markers.Initialize2(Array As Marker(Marker1, Marker2))

And that maintains the original OverlayItemWrapper class.

Whereas adding individual Markers to the List causes them to be cast to OverlayItems:

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

So i'll put a test project together and debug from there.

Meanwhile it's a glorious sunny day in Norfolk UK and i'm gonna spend some time in the sun.

Martin.
 

lagore

Active Member
Licensed User
Longtime User
PathOverlay to Great Circle?

Hi is there the option to create the PathOverlay as a great circle on the map?Thanks
 

bluedude

Well-Known Member
Licensed User
Longtime User
Multiple markers

So the conclusion for now it isn't possible to add a range of markers generated from a file, json or whatsoever?

Only way to do it is defining markers manually?

Ok, clear. Will stick to Google Maps for a while then.

Enjoy the weather.

Cheers,
 

bluedude

Well-Known Member
Licensed User
Longtime User
Permissions to use libraries

Hi,

I have sent you a private message for the use of your libraries.

Cheers,
 

walterf25

Expert
Licensed User
Longtime User
Awesome library

Hi there, i just wanted to say thanks for this amazing library, i added it to the app i'm working on, and it works really great, however i would like to find out if there's anything that can be done to make the maps load a little bit faster, and is there a way to add my own maps to it?

again, thanks for this amazing library.

Cheers,
Walter
 

warwound

Expert
Licensed User
Longtime User
So the conclusion for now it isn't possible to add a range of markers generated from a file, json or whatsoever?

Only way to do it is defining markers manually?

Ok, clear. Will stick to Google Maps for a while then.

Hi.

I'll fix the library - hopefully today i'll find what's going wrong.

Meanwhile here's a workaround that does work:

B4X:
   Dim Icon As BitmapDrawable
   Icon.Initialize(LoadBitmap(File.DirAssets, "my_icon.png"))
   
   Dim AnArray(11) As Marker
   
   For i=0 To 10
      Dim Marker1 As Marker
      Marker1.Initialize("Home sweet home", "bla", 52+i, i, Icon)
      AnArray(i)=Marker1
   Next

   Dim Markers As List
   Markers.Initialize2(AnArray)

   'add markers to overlay
   ovlMarkers.AddMarkers(Markers)

As i said before - it's strange that using an array maintains the Marker's wrapper class but adding individual Markers to a List causes them to change class.

Martin.
 

Attachments

  • bluedude_fixed.zip
    7.3 KB · Views: 390

warwound

Expert
Licensed User
Longtime User
Hi there, i just wanted to say thanks for this amazing library, i added it to the app i'm working on, and it works really great, however i would like to find out if there's anything that can be done to make the maps load a little bit faster

Are you finding that the MapView takes a while to initialize and be displayed or that the tiles are taking a while to download and display as you pan and zoom the map?

The time it takes for the MapView to initialize is device dependant i think.
The more Overlays and features you add to a map the slower it will be to initialize.
And in theory if you were to add many many Markers or PathOverlays to a map then you'd find the map slow to pan and zoom.

Slow tile loading is a different matter.

It could be that your device's network connection is slow - that's more likely to apply to a 3G connection than a WiFi connection.

The servers that serve the tiles could be slow and overloaded.
This will vary over time as the load on the tile servers varies.

Look at my offline maps example.
Try using offline tiles and see if it speeds the tile loading up - if so then the problem is with the tile servers and there's little that can be done.
(When testing offline tiles be sure to use SetDataConnectionEnabled(False) and delete or temporarily rename the osmdroid cache folder for the TileSource you have downloaded tiles - all explained in my example).

and is there a way to add my own maps to it?

Yes you can use your own tile layer.
The library currently has no methods to allow you to do so but the underlying code is all there.

How would you want to add your own tiles?

Would you want to pack them as an offline tile archive and include them with your application?

Or are the tiles available online and you'd want the map to fetch them via the internet?

Are your tiles 256 pixels square - the same as most tile sources - or are they a different size?

How are your tiles named?
The Slippy map tile naming convention is what OSMDroid expects but there are workarounds if your tiles are named differently.

Martin.
 

warwound

Expert
Licensed User
Longtime User
OSMDroid updated to version 1.03

Hi is there the option to create the PathOverlay as a great circle on the map?Thanks

PathOverlay has a new method:

AddGreatCircle (StartPoint As GeoPoint, EndPoint As GeoPoint, NumberOfPoints As Int)

Add NumberOfPoints points to the path to create a great circle from StartPoint to EndPoint.
Does NOT clear existing points of the path.

GeoPoint has 3 new methods:

GetBearingTo (GeoPoint1 As GeoPoint)

Get the bearing (in degrees) from this GeoPoint to GeoPoint1.

GetDestinationPoint (Distance As Double, Bearing As Float)

Get a new GeoPoint that is the specified Distance (in meters) and Bearing (in degrees) away from this GeoPoint.

GetDistanceTo (GeoPoint1 As GeoPoint)

Get the distance (in metres) from this GeoPoint to GeoPoint1.
(I'm 99% certain this is Haversine distance).

And BoundingBox has four new methods:

Contains (Latitude As Double, Longitude As Double)

Returns True if this BoundingBox contains the Latitude, Longitude.

Contains2 (GeoPoint1 As GeoPoint)

Returns True if this BoundingBox contains GeoPoint1.

GetNorthWest As GeoPoint

Get the top left point of this BoundingBox as a GeoPoint.

GetSouthEast As GeoPoint

Get the bottom right point of this BoundingBox as a GeoPoint.

New version is attached to the first post in this thread.
And a great circle code example will be uploaded shortly.

Martin.
 

walterf25

Expert
Licensed User
Longtime User
Appplication forclosing

Hi Martin, i'm having a problem when initializing the MapView, it seemed to have been working fine at work when i was running it, i came home and now the application forcloses at that point, below i'm pasting the log i see when it crashes maybe you can help me figure out why it's doing this.

this is my code in the Sub Activity_Create
B4X:
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("MapView")
If File.ExternalWritable=False Then
Log("WARNING NO EXTERNAL STORAGE AVAILABLE")
End If
'lstSchedule.Initialize("lstschedule")

locationlist.Initialize 
location5.Initialize 
VehicleIDs.Initialize 
wbMapView.Initialize("wbMapView")   'appliation forcloses at this point!!!!!!!
Activity.AddView(wbMapView, 0, 0, 100%x, 100%y)
 wbMapView.SetZoomEnabled(True)
 wbMapView.SetMultiTouchEnabled(True)
 wbMapView.Zoom = 18
 MyLocationOverlay1.Initialize(wbMapView, "mylocationoverlay1")
 
 
 MarkersOverlay1.Initialize(wbMapView, "MarkersOverlay1")
 wbMapView.AddOverlay(MyLocationOverlay1)
 wbMapView.AddOverlay(MarkersOverlay1)
MyLocationOverlay1.CompassEnabled = True 
 icon.Initialize(LoadBitmap(File.DirAssets, "lametrobus.jpg"))
Markers.Initialize2(Array As Marker(Marker1))
 
 

'wbMapView.Width = 100%x
'wbMapView.Height = 100%y
'wbMapView.Initialize("wbMapView")
Parser4.Initialize 
stoptags5.Initialize 
refreshinterval.Initialize("refreshinterval", 30000)

'GPS2.Initialize("GPS2")
'GPS2.Start(5000, 10)

'wbMapView.LoadUrl("file:///android_asset/location_map.htm?lat="&stooptags.latitude1&"&lng="&stooptags.longitude1&"&zoom=8")
hc4.Initialize("hc4")
url = "http://webservices.nextbus.com/service/publicXMLFeed?command=vehicleLocations&a=lametro&r=" & Main.busnumber & "&t=0"
 req4.InitializeGet(url)
 hc4.Execute(req4, 3)
 ProgressDialogShow("Preparing Map.....")

End Sub

and here is the log when it crashes

Could not find method org.slf4j.LoggerFactory.getLogger, referenced from method org.osmdroid.DefaultResourceProxyImpl.<clinit>
VFY: unable to resolve static method 4285: Lorg/slf4j/LoggerFactory;.getLogger (Ljava/lang/Class;)Lorg/slf4j/Logger;
VFY: replacing opcode 0x71 at 0x0002
VFY: dead code 0x0005-0008 in Lorg/osmdroid/DefaultResourceProxyImpl;.<clinit> ()V
Could not find method org.slf4j.Logger.error, referenced from method org.osmdroid.DefaultResourceProxyImpl.getBitmap
VFY: unable to resolve interface method 4277: Lorg/slf4j/Logger;.error (Ljava/lang/String;)V
VFY: replacing opcode 0x72 at 0x004a
VFY: dead code 0x004d-0050 in Lorg/osmdroid/DefaultResourceProxyImpl;.getBitmap (Lorg/osmdroid/ResourceProxy$bitmap;)Landroid/graphics/Bitmap;
Exception Ljava/lang/NoClassDefFoundError; thrown while initializing Lorg/osmdroid/DefaultResourceProxyImpl;
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x4001a560)
wake lock acquired
decideWhoNeedsPolling(): polling PushService
Finished sending keep alive
modifyApp(): PushService
calculateShortestInterval(): shortest interval is 75121
org.apache.harmony.nio.internal.SocketChannelImpl@40a7b860: Wrote out 22 bytes of data with 0 bytes remaining.
wake lock released
waiting to render 0x17960
Sending signal. PID: 2332 SIG: 9
channel '40e38ce0 dandre.dev.com/dandre.dev.com.main (server)' ~ Consumer closed input channel or an error occurred. events=0x8
channel '40e38ce0 dandre.dev.com/dandre.dev.com.main (server)' ~ Channel is unrecoverably broken and will be disposed!
Previously focused view reported id 1 during save, but can't be found during restore.
** Activity (direction) Create, isFirst = true **
GC_EXTERNAL_ALLOC freed 223K, 48% free 2873K/5511K, external 2741K/2773K, paused 26ms
direction_activity_create (B4A line: 52)
Parser1.Initialize



java.lang.NullPointerException
at dandre.dev.com.direction._activity_create(direction.java:274)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:105)
at dandre.dev.com.direction.afterFirstLayout(direction.java:84)
at dandre.dev.com.direction.access$100(direction.java:16)
at dandre.dev.com.direction$WaitForLayout.run(direction.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:3806)
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:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
java.lang.NullPointerException

hopefully you can help me figure out what's going on, i don't see why it should crash when the mapview is initialized.

thanks,
Walter
 

warwound

Expert
Licensed User
Longtime User
Could not find method org.slf4j.LoggerFactory.getLogger, referenced from method org.osmdroid.DefaultResourceProxyImpl.<clinit>

Looks like the logger library slf4j-android-1.5.8.jar is missing from your B4A additional libraries folder?

Martin.
 

walterf25

Expert
Licensed User
Longtime User
Error

Hi Martin, i checked for that file and is definately in there, i only see this problem with basic4android 1.7, i tried it again at work, i just upgraded to version 1.9 and it works like a charm, i following the instructions in the text file as to what files to copy to the libraries folder according to which version, and it still gives me that error, on version 1.7, can you check it out, i guess it doesn't matter becuase i will upgrade to version 1.9 when i get home.

thanks,
Walter
 

walterf25

Expert
Licensed User
Longtime User
app still foreclosing

Hi there Martin, i checked again to make sure that all the necessary files are in my additional libraries folder, and they are all in there, i'm using basic4android version 1.7 can you please check why my app forecloses when i initialize the mapview, i really need to figure this out, i really want to keep using this library since is really easy to use.

thanks,
Walter
 

warwound

Expert
Licensed User
Longtime User
OSMDroid updated to version 2.00

This is an important update even though it has no new features or methods.

For a technical insight into why the update was required please read this thread: http://www.b4x.com/forum/libraries-...1-wrappedobject-becomes-object.html#post93413.

Your existing code should work without modification unless you have incorporated the example code for MarkersOverlay or MarkersFocusOverlay into your project.

I have updated both those threads to make them work with version 2.00, the only change required was the way that the List was Initialized with the Marker objects.

Old code:

B4X:
Markers.Initialize2(Array As Marker(Marker1, Marker2))

New code:

B4X:
Markers.Initialize2(Array As Object(Marker1, Marker2))

The library is now more compatible with the way that B4A handles object wrappers.

Version 2.00 is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
Hi there Martin, i checked again to make sure that all the necessary files are in my additional libraries folder, and they are all in there, i'm using basic4android version 1.7 can you please check why my app forecloses when i initialize the mapview, i really need to figure this out, i really want to keep using this library since is really easy to use.

thanks,
Walter

You'll need the dummy XML files if you are using B4A version 1.7, take a look at this thread: http://www.b4x.com/forum/basic4andr...smdroid-mapview-b4a-tutorial-4.html#post93126.

Martin.
 

warwound

Expert
Licensed User
Longtime User
I think it's time for me to address the licensing issues of the native Android OSMDroid library...

It's licensed under the GNU Lesser General Public License.

And the OpenStreetMap tiles are covered by a Tile usage policy.

What does this mean to us developers?

Who knows!
The wording of the LGPL is rather vague - it covers so many usage cases in general but not a single usage case in detail.

I started a thread on the OSMDroid Google group over a week back and got not a single reply: https://groups.google.com/group/osmdroid/browse_frm/thread/67b806821900b5a7?hl=en#.

An older thread on the same group has more info but nothing that i think applies to my usage of the native Android library in my B4A library: How free is OSM - osmdroid | Google Groups.

From what i can gather i must make available the source code of any native Android library classes that i have modified.
I have currently modified just 5 classes and have made the source code of those classes available here: android.martinpearman.co.uk/b4a/osmdroid/src/.

I shall try to get in contact with the owners of the original Android OSMDroid project over the next week and will update this thread if there are any problems relating to the license.

Martin.
 
Last edited:

bluedude

Well-Known Member
Licensed User
Longtime User
Tile usage policy MapNik

I checked out the usage policy of MapNik and I think i'm not going to use it because it looks pretty strict to me.

Probably i'm going to use either MapQuest (they are pretty good overall) or Cloudmade.

All this stuff proves that there is no such thing as "free".

Just got a basic OSM integration ready with the updated library and it works although my app. crashes more often. A standalone project with only mapping doesn't have this issue.

Not sure why it happens but will do some more testing. When disabling the MyLocation overlay and MapScale it does not crash in my full app.

Cheers,
 

warwound

Expert
Licensed User
Longtime User
OSMDroid updated to version 3.00
Please read carefully - a lot has changed...

  • The library is now contained in the two files OSMDroid.jar and OSMDroid.xml.
    There is no longer a dependency on the two files NativeOSMDroid.jar and slf4j-android-1.5.8.jar, i have managed to compile the library so these jars are part of the library.
    Delete NativeOSMDroid.jar and slf4j-android-1.5.8.jar from your B4A additional libraries folder when you update to version 3.00.
    If you were also using a version of Basic4Android older than version 1.8 then you can also delete the two files NativeOSMDroid.xml and slf4j-android-1.5.8.xml.
  • The library now requires that you add some files to your B4A project's Objects folder.
    The new library download contains a folder res which contains folders drawable-nodpi and layout.
    Copy both drawable-nodpi and layout to your B4A project's Objects folder.
    Ensure that the contents of these two folders remain read-only.
    Now that the map icons are no longer encoded in the library, the library should now work with older versions of the Android API.
    Prior to library version 3.00, Froyo and later were required otherwise the MapView could not decode the encoded icons.

So that's installation/upgrading explained, now onto the two new features.

  • MarkersEventsOverlay is a replacement for the MarkersOverlay.
    It has the same methods and properties BUT it's two events return different values to the B4A event handler Sub.

    MarkersEventsOverlay Events:
    • Click (Marker1 As Marker)
    • LongClick (Marker1 As Marker)

    MarkersOverlay Events
    • Click (Title As String, Description As String, Point As GeoPoint)
    • LongClick (Title As String, Description As String, Point As GeoPoint)

    As you can see the new MarkersEventsOverlay passes the original Marker back to the event handler rather than the original Marker's Title, Description and Point values.
  • MarkersBalloonOverlay is the most important update with version 3.00, it replaces the MarkersFocusOverlay which although functional was very limited.
    MarkersBalloonOverlay implements MapViewBalloons.
    With MarkersBalloonOverlay you can now create a truly professional looking map with customisable balloon.
    You can use the template balloon layout included in the layout folder or you can customise it.
    Add new Views to create a custom balloon, add a Tag String value to any View in the XML and you can listen for Click and LongClick events on that View.

There's too much to document so i'll be uploading 2 or 3 examples to my OSMDroid tutorial thread - i'll probably do that tomorrow morning.

Meanwhile the javadoc for the new version of the library is available to browse here.

Both MarkersOverlay and MarkersFocusOverlay are still part of OSMDroid 3.00 BUT i would consider them deprecated and at some point in a future update i would like to remove them from the library.
For now they are still part of the library so as not to break existing code.
If you use either of these overlays in your maps then please try to update your map to use either MarkersEventsOverlay or MarkersBalloonOverlay.


Version 3.00 of OSMDroid is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
OSMDroid updated to version 3.10

Version 3.10 adds some new features and improves on the version 3.00 update.

A new feature is the ability to add a new tile source provider to the MapView.

XYTileSource is the new object that defines a new tile source provider.

XYTileSource has just a single method, it's Initialize method:

Initialize (Name As String, MinZoomLevel As Int, MaxZoomLevel As Int, TileSize As Int, TileFilenameEnding As String, BaseUrl As String)

You can only add a new tile source provider to the MapView if that tile source provider uses the Slippy map tile naming convention.

Please do not ask me how to add tiles from providers such as Google Maps to the MapView. Use of such tiles in an OSMDroid map without specific permission from the provider is against their terms and conditions of use!

So you have your own Slippy map tile provider and have created an XYTileSource object, you now use the new MapView AddXYTileSource method to add your object to your MapView:

AddXYTileSource (MyXYTileSource As XYTileSource)

I will upload an example to the OSMDroid tutorial thread later.

Version 3.10 includes various updates to the MarkersBalloonOverlay which was introduced in version 3.00.

It was important to abstract some functionality - the MarkersBalloonOverlay XML layout file was hardcoded to balloon_overlay.xml.

With version 3.10 the MarkersBalloonOverlay Initialize method is changed:

Initialize(aMapView As MapView, EventName As String, BalloonLayoutName As String)

The Initialize method now requires a parameter BalloonLayoutName .

Only 31 B4A users have downloaded version 3.00 todate so i think it reasonable to change that method - the increased functionality it provides more than outweighs the effort it will take those users to update any version 3.00 project code.

Next is a new object the BalloonMarker.

Let's say you create a MarkersBalloonOverlay and don't want to use the same balloon layout for every Marker on that Overlay...

If you want a Marker to display a balloon layout other than the balloon layout defined in the MarkersBalloonOverlay Initialize method then that Marker should be a BalloonMarker and NOT a Marker.

BalloonMarker is the same as Marker BUT has one new property LayoutName:

B4X:
MyBalloonMarker.LayoutName="my_custom_balloon_layout"

If MyBalloonMarker is clicked then the layout file my_custom_balloon_layout.xml is used to create it's balloon layout.

If a BallonMarker's LayoutName is not defined then the default balloon layout will be displayed.

Again i shall upload an example to the tutorial thread later.

That's the main changes with version 3.10, other minor changes are:

  • Fixed the position of the balloon so it's properly anchored to the icon of the clicked Marker rather than directly anchored to the Marker's base.
  • When the balloon is displayed the MapView will pan (with animation) to the MapView center.
    Works well unless the balloon height is bigger than half the MapView height, and at the moment this panning cannot be disabled.
    A future update may address these two issues - a lot depends on feedback from users.

I have also re-structured the library download zip file.
Check out the readme.txt file to see which of the included resources you may need to add to your project.

Version 3.10 is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
OSMDroid updated to version 3.20

There are two changes with this update.

I've added a new method to the XYTileSource object:

Initialize2 (Name As String, MinZoomLevel As Int, MaxZoomLevel As Int, TileSize As Int, TileFilenameEnding As String, BaseUrls() As String)

An Array of Strings is passed for the BaseUrls parameter.

Many online tile providers serve tiles from more than one domain.
Often serving tiles from sub-domains.
The HTTP connection standard defines that no more than two connections may be made to a single domain at any one time.
So tile providers can serve tile from a number of sub-domains, the limit of 2 connections applies to each sub-domain and this effectively means a client can request up to 2 tiles from each sub-domain - speeding up the serving of tiles to the client.

I've also updated the ScaleBarOverlay, adding a new method:

SetPosition (Position As Int)

Set the position to display the scale bar within the MapView.
Possible values are:
ScaleBarOverlay.BOTTOM_LEFT
ScaleBarOverlay.TOP_LEFT

Default value is ScaleBarOverlay.TOP_LEFT

Prior to this update the ScaleBarOverlay was always positioned at the top-left of the MapView, you can now position it bottom-left if desired.

Other than these two new methods there is nothing else to document.
The native Android OSMDroid projected has itself been updated from version 3.0.7 to 3.0.8 so this library update is compiled with the new native core 3.0.8.

To update from the last library version 3.10 to the new 3.20 simply download the new files and overwrite the old files - nothing more is required.

Version 3.20 is attached to the first post in this thread.

I shall upload examples of the two new methods to the OSMDroid tutorial thread shortly.

Martin.
 

monki

Active Member
Licensed User
Longtime User
Hi Warwound,
thanks for the OSM-Lib.
I would like to know if it's possible the map, or parts of it as a bitmap (JPG, PNG ..) to export.

Many greetings monki;)
 
Top