Android Tutorial OSMDroid - MapView for B4A tutorial

You can find the OSMDroid library thread here: http://www.b4x.com/forum/additional...tes/16309-osmdroid-mapview-b4a.html#post92643.

AIM: Create and initialize a MapView, enable the map zoom controller and multitouch controller, set a zoom level then center the map on a location.

B4X:
Sub Process_Globals
End Sub

Sub Globals
   Dim MapView1 As MapView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If File.ExternalWritable=False Then
      '   OSMDroid requires the use of external storage to cache tiles
      '   if no external storage is available then the MapView will display no tiles
      Log("WARNING NO EXTERNAL STORAGE AVAILABLE")
   End If
   
   '   no EventName is required as we don't need to listen for MapView events
   MapView1.Initialize("")
   Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
   
   '   by default the map will zoom in on a double tap and also be draggable - no other user interface features are enabled
   
   '   enable the built in zoom controller - the map can now be zoomed in and out
   MapView1.SetZoomEnabled(True)
   
   '   enable the built in multi touch controller - the map can now be 'pinch zoomed'
   MapView1.SetMultiTouchEnabled(True)
   
   '   set the zoom level BEFORE the center (otherwise unpredictable map center may be set)
   MapView1.Zoom=14
   MapView1.SetCenter(52.75192, 0.40505)
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

The code is pretty self-explanatory.

I've added the code to check if the device has available external storage as OSMDroid will not display any tiles if no external storage is available.
External storage is used to save/cache all downloaded tiles - no external storage means no map!
(I'll omit that check from future tutorials but it's something to bear in mind - not that i know of any Android devices that have no external storage).

Create and initialize a MapView, add it to the Activity 100% width and 100% height.
Enable the zoom and multi-touch controller.
Zoom in to level 14 then set the MapView center to a location (sunny Norfolk, UK!).

I've found that setting the map center and then immediately setting the zoom level does not work as expected.
I think that while the MapView is setting the map center it also zooms in so the end result is unpredictable.

Pan and zoom the map, now rotate your device and you'll see the map returns to it's initial state of zoom level 14, center (52.75192, 0.40505).

I shall show you how to save and restore the MapView state next...

Martin.
 

Attachments

  • 01 - SimpleMap.zip
    5.8 KB · Views: 4,794
Last edited:

enemotrop

Member
Licensed User
Longtime User
I need to add a new layer to an OSMDroid map, in order to represent if a geographical zone is included in a given list of coordinates intervals, like it's usually drawn in coverage representation maps.

It would be something like this:

BEFORE (OSMDroid Map without the new layer):
capmap.jpg


AFTER (with a semitransparent layer):
capmap2.jpg


Is it possible?
 

warwound

Expert
Licensed User
Longtime User
You have two options:

1) Most straightforward is to use a PathOverlay to render these zones as polygons.

2) Far more complicated is to render a set of semi-transparent map tiles with these zones drawn on the tiles and then add the tiles to the map as a TilesOverlay.

Martin.
 

enemotrop

Member
Licensed User
Longtime User
I had no luck trying to use the PathOverlay... What I've added to the code was:

In Sub Globals:

B4X:
Dim PathOverlay1 As PathOverlay

In Sub Activity_Create:

B4X:
Dim latit As Double, longi As Double
Dim puntocober, puntocober2 As GeoPoint
Dim strpuntocober As String 
PathOverlay1.Initialize(MapView1, Colors.Black)
MapView1.AddOverlay(PathOverlay1)
PathOverlay1.StrokeWidth=4
PathOverlay1.Alpha=128
For a = 0 To Main.listaGeoESP.Size - 1 'Main.listaGeoESP contains strings representing the coverage, corresponding to filenames in this format: "N45E022.zip"
'The idea is add a polygon for each file, covering all its area
  strpuntocober = Main.listaGeoESP.Get(a)
  latit = strpuntocober.SubString2(1,3) 'We take the latitude from the string
  If strpuntocober.SubString2(0,1) = "S" Then
    latit = -1 * latit  'If it was South, we convert it to negative
  End If
  longi = strpuntocober.SubString2(4,7) 'We do the same with the longitude
  If strpuntocober.SubString2(3,4) = "W" Then
    longi = -1 * longi
  End If
  puntocober.Initialize(latit, longi) 'Assign the values to the first point  
  puntocober2.Initialize(latit + 1, longi + 1) 'The second point is exactly 1 degree greater to the North and to the East
  PathOverlay1.AddGreatCircle(puntocober, puntocober2, 100)
Next

This code doesn't draw anything over the map. The values are passed correctly to the AddGreatCircle method. I've tried also with AddPoint3 with the same result.

What is wrong??
 

eurojam

Well-Known Member
Licensed User
Longtime User
osmdroid OSMPublicTransport does not work anymore

I have remarked, that the OSMPublicTransport does not work anymore with osmdroid. Does anybody know how to fix that problem?

Cheers
Stefan
 

warwound

Expert
Licensed User
Longtime User
I have remarked, that the OSMPublicTransport does not work anymore with osmdroid. Does anybody know how to fix that problem?

Cheers
Stefan

Yet another free tileserver has started to restrict access to it's map tiles :(.

I just tried OSMPublicTransport and the map displays tiles with a message 'The map was designed for online use'.
The tile server blocks access to the tiles for some reason, it's designed to serve tiles to web based maps and does not recognise OSMDroid as being allowed access to tiles.

There's not a lot you can do about that, these tiles are requested from the tileserver at: http://tile.xn--pnvkarte-m4a.de/tilegen/ so that tileserver is no longer any use.

You can instead find (or try to find!) another tileserver and use this other tileserver as an XYTileSource.
You'll always fnd that relying on a 3rd party tileserver can at any time fail.
More and more free tileservers are restricting access to their tiles to prevent their servers from being overloaded, they tend to block anything except (javascript) web based maps, assuming that requests from other sources (such as OSMDroid) are bulk downloading tiles and that's against their terms and conditions of use.

Have a look at Cloudmade tiles.
Unless Cloudmade have changed their usage policy they allow free access to tiles from OSMDroid, there's some info on using Cloudmade tiles here: http://www.b4x.com/forum/basic4andr...smdroid-mapview-b4a-tutorial-2.html#post92864.

Generally you can expect the Cloudmade tileservers to perform quicker and more reliably than many other free tileservers so i'd recommend Cloudmade.
Cloudmade have various types of tiles - all based on OSM data - you can even design your own tile style and use these custom styled tiles in OSMDroid.

Martin.
 

Attachments

  • osmpublictransport.png
    osmpublictransport.png
    30.4 KB · Views: 361

warwound

Expert
Licensed User
Longtime User
What is "MyLocation" - is it a GeoPoint or are you referring to the MyLocationOverlay and you want the map to start centered on the user's current location?

Martin.
 

PaulD

Member
Licensed User
Longtime User
Martin,

Using the MyLocationOverlay, I would like the map to be centered on the current GeoPoint (Current GPS Location) on Run...

Then, is there a way to shut down the GPS until a "Refresh" button is pushed OR a controllable amount of time? Once the time or refresh is pushed, then re-center on the new current location?

Thank you for your help!
 

warwound

Expert
Licensed User
Longtime User
Take a look at the attached project.
I've updated the MyLocationOverlay example.

It starts and sets the map center to (0, 0) at zoom level 10 and waits for the MyLocationOverlay to get a GPS fix.

When a GPS fix is obtained the map is centered on that location.
If this GPS fix is the first fix found then the map waits again for another GPS fix, otherwise MyLocationOverlay is disabled.

The first GPS fix i find is inaccurate so setting the map center on the next fix tends to be better.

You could soon add an option to the code to re-enable MyLocationOverlay - if re-enabled then a GPS fix will cause the map center to be re-set and again MyLocationOverlay will be disabled.

Martin.
 

Attachments

  • MyLocationMapCenter.zip
    39 KB · Views: 570

PaulD

Member
Licensed User
Longtime User
SWEET!! Thank you so much Martin!! I have been trying to figure that out for days!!

Although it's not critical to what I am doing, I really like the "compass" and in the example you posted for me, it appears that the compass has been enabled, yet I do not see it when I "run" the example on my phone?

Thank you for all of your help!!
 

warwound

Expert
Licensed User
Longtime User
The compass when added to the map is hidden by default it seems.

Change line 49 from:

B4X:
CompassEnabled=MyLocationOverlay1.CompassEnabled

to:

B4X:
CompassEnabled=True

You should now see it.

Martin.
 

warwound

Expert
Licensed User
Longtime User
Martin,

What line of code should I place on my manual "refresh" button to re-engage the GPS and set the new current location?

B4X:
MyLocationOverlay1.MyLocationEnabled=True

And if you want the map to auto-pan to the new GPS fix then also add:

B4X:
MyLocationOverlay1.FollowLocationEnabled=True

Note that if the user touches the device screen then MyLocationOverlay1.FollowLocationEnabled is automatically set to False.

Martin.
 

PaulD

Member
Licensed User
Longtime User
Thank you! Thank you! Thank you!

The location stuff is working GREAT!! And the "refresh" then recenter on current location also working GREAT!!

For some reason the compass is still not showing up...

Now all I need to do is draw address locations from a data base and have it display as balloons on the map... any experience with that?
 

warwound

Expert
Licensed User
Longtime User
I'm not sure why the compass doesn't display - what device and version of android are you testing this on?
OSMDroid has a few bugs and newer versions of android (Jelly Bean) tend to make the bugs worse.
If you want to upload your project i'll try it and see if i can see what's wrong.

You can find a short tutorial on adding Markers to a map that open an 'info balloon' when clicked here: http://www.b4x.com/forum/basic4andr...smdroid-mapview-b4a-tutorial-6.html#post96568.

Martin.
 

PaulD

Member
Licensed User
Longtime User
When loaded in the Debug mode on my Samsung Galaxy S2, if I use the "back" soft button on the phone to get back to the main menu, then re-open the app, sometimes I see the compass... other times I have to do it twice to see the compass...

My S2 is running 4.0.4

I will start reading up on the "info balloon's"

Thank you!
 

Attachments

  • RedTagApp.zip
    232.8 KB · Views: 446

warwound

Expert
Licensed User
Longtime User
That's odd, on my S3 (4.1.2) i see neither compass or scale bar though they are both enabled.

I tried re-ordering some of the code to see if that fixed it but still no compass and no scale bar.

Can you try the attached project - i see both a compass and scale bar top left of the map.

Martin.
 

Attachments

  • MyLocationMapCenter2.zip
    39 KB · Views: 462

warwound

Expert
Licensed User
Longtime User
I don't know!

I changed the order of various parts of the OSMDroid library in your RedTagApp and it didn't make either compass or scale bar appear.
I wondered if the MapView was actually being created larger than the area on the Activity and the compass and scale bar were 'displayed' but not visible as they were on a part of the MapView that was not visible (does that make sense?).

But you add the MapView to the Activity with what looks like perfectly acceptable code - the MapView left and top are within the Activity and the MapView width and height all fit within the visible Activity:

B4X:
Activity.AddView(MapView1, 0, 48dip, 100%x, 100%y-48dip)

You could try adding a Panel to the Activity where you are currently adding the MapView and then adding the MapView to the Panel:

B4X:
Dim Panel1 As Panel
Panel1.Initialize("")
Activity.AddView(Panel1, 0, 48dip, 100%x, 100%y-48dip)
Panel1.AddView(MapView1, 0, 0, Panel1.Width, Panel1.Height)

I suspect though that that won't fix it and the problem is elsewhere...

[edit]
Just commented out the code to add the MinimapOverlay to the MapView:

B4X:
'MapView1.AddOverlay(MinimapOverlay1)

On my old ZTE Blade running Gingerbread i now see both compass and scale bar!
So i tried it again on my S3 - no compass and no scale bar.

You might want to look through the known bugs in the android java OSMDroid library and see if it's been reported and see if a solution exists: Issues - osmdroid - OpenStreetMap-Tools for Android - Google Project Hosting
[/edit]

Martin.
 

davelew1s

Active Member
Licensed User
Longtime User
Marker problem

Hi!
I have only just come across this thread(thanks Martin some geat examples and explainations) I've put together a small app for use on a boat..most of it works ok, I can drop markers to show 'start drift' 'fish found' 'end drift'
no problem but I cannot find a way to delete a single marker. I tried this:-

For i = 0 To markers .Size - 1
Dim row() As string
row = markers.Get(i)
Dim NewRow As String
For ii = 0 To row.Length-1
NewRow = NewRow & row(ii)
If ii < row.Length-1 Then
NewRow = NewRow & " , "
End If
Next
Log(NewRow)
Next

to see if I could find and remove a marker from "markers "but this won't work. Any help??
Thanks Dave.
 
Top