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,642
Last edited:

warwound

Expert
Licensed User
Longtime User
Can you export your project as a ZIP file and upload it to this thread?

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
Can you export your project as a ZIP file and upload it to this thread?

Martin.

The prj is your "Offline maps.zip", nothing more.

i've tried to comment this line :
B4X:
Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
and the prj compiled without error!
 

warwound

Expert
Licensed User
Longtime User
I'm not sure what's going wrong here!

Can you successfully compile any of the other examples?

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
I'm not sure what's going wrong here!

Can you successfully compile any of the other examples?

Martin.

here's a sample code :

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim MapView1 As MapView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

got the same error.
i'm using b4a 1.70, win xp sp3.
 

warwound

Expert
Licensed User
Longtime User
Ah you need to Initialize the MapView BEFORE adding it to the Activity:

B4X:
MapView1.Initialize("EventNameHereIfRequired")

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
Ah you need to Initialize the MapView BEFORE adding it to the Activity:

B4X:
MapView1.Initialize("EventNameHereIfRequired")

Martin.

It's seems that I'm the only one who have problem!

Modified code, same error:

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim MapView1 As MapView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   MapView1.Initialize("MapView1")

'This line causes the problem
   Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
End Sub

Sub MapView1_ZoomChanged

End Sub
 

warwound

Expert
Licensed User
Longtime User
Clean your project and zip then upload it to this thread so i can look it in detail.

You are 100% sure that your B4A additional libraries folder contains these four files are you?

  • OSMDroid.jar
  • OSMDroid.xml
  • NativeOSMDroid.jar
  • slf4j-android-1.5.8.jar

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
Clean your project and zip then upload it to this thread so i can look it in detail.

You are 100% sure that your B4A additional libraries folder contains these four files are you?

  • OSMDroid.jar
  • OSMDroid.xml
  • NativeOSMDroid.jar
  • slf4j-android-1.5.8.jar

Martin.

tanx, please get the attachment.
There's a file (lib_list.txt) in the zip that contains the name of files of the lib folder.
 

Attachments

  • Test.zip
    11.9 KB · Views: 583

warwound

Expert
Licensed User
Longtime User
The ZIP archive contained different code to that which you posted previously, it still gave an error as you were not initializing Panel1.

Initialize Panel1 as it works fine for me:

B4X:
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim MapView1 As MapView
   Dim Panel1 As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
   MapView1.Initialize("MapView1")
   
   Panel1.Initialize("")
   
   Panel1.AddView(MapView1, 0, 0, 100%x, 100%y)
   Activity.AddView(Panel1, 0, 0, 100%x, 100%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub MapView1_ZoomChanged

End Sub

All B4A Views created in code must be initialized:

  • Before adding them to an Activity or other container View.
  • Before accessing their methods and properties.

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
The ZIP archive contained different code to that which you posted previously, it still gave an error as you were not initializing Panel1.

Initialize Panel1 as it works fine for me:

B4X:
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim MapView1 As MapView
   Dim Panel1 As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
   MapView1.Initialize("MapView1")
   
   Panel1.Initialize("")
   
   Panel1.AddView(MapView1, 0, 0, 100%x, 100%y)
   Activity.AddView(Panel1, 0, 0, 100%x, 100%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub MapView1_ZoomChanged

End Sub

All B4A Views created in code must be initialized:

  • Before adding them to an Activity or other container View.
  • Before accessing their methods and properties.

Martin.

Oops! I've changed the code to test it with a panel, but even with the above code I still have the error!
Tanx for your time, I'll try to find the problem.
 

warwound

Expert
Licensed User
Longtime User
Your file lib_list.txt lists the official native OSMDroid library and javadoc file in your B4A additional libraries folder.

I very much doubt if they are causing the problem but you could try removing them.

  • osmdroid-android-3.0.7.jar
  • osmdroid-android-3.0.7-javadoc.jar

If that fails try and re-download all the library files - there's a possibility that your downloaded files got corrupted...

Martin.
 

Ohanian

Active Member
Licensed User
Longtime User
Your file lib_list.txt lists the official native OSMDroid library and javadoc file in your B4A additional libraries folder.

I very much doubt if they are causing the problem but you could try removing them.

  • osmdroid-android-3.0.7.jar
  • osmdroid-android-3.0.7-javadoc.jar

If that fails try and re-download all the library files - there's a possibility that your downloaded files got corrupted...

Martin.

i've installed a fresh copy of b4a on a xp sp3 with jdk 1.6.0_21 and no extra lib, still the same error :confused:
 

thedesolatesoul

Expert
Licensed User
Longtime User
I think you need to create a dummy xml file with the following name:
B4X:
NativeOSMDroid.xml
and following content:

B4X:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <doclet-version-NOT-library-version>1.00</doclet-version-NOT-library-version>
    <version>1.0</version>
</root>

and put it in your additional libraries folder.
 

warwound

Expert
Licensed User
Longtime User
Martin,
He is using B4A 1.7.
I have an inkling that the MapView class is defined in NativeOSMDroid.jar
I think an xml file will be needed to expose that for B4A 1.7

Well my library uses this code to include the two additional files:

B4X:
@DependsOn(values = { "NativeOSMDroid", "slf4j-android-1.5.8" })

The DependsOn attribute is relatively new to B4A so maybe that's the problem?

Martin.
 

margret

Well-Known Member
Licensed User
Longtime User
Hello, I created and added the xml file to the XtraLibs folder and still got this error. Maybe it has something in it that will give you an idea of why it's happening.
 

Attachments

  • mapserror.jpg
    mapserror.jpg
    67.1 KB · Views: 404

warwound

Expert
Licensed User
Longtime User
Here's another code example for you all!

It's often required that your application requires a location - that could be a user selected location or the user's actual location obtained using GPS.

This example uses the SimpleLocationOverlay to enable the user to manually pan and zoom the map to a location, and the MyLocationOverlay to get the user's current location using GPS.

MyLocationOverlay and SimpleLocationOverlay require the resources in the drawable-nodpi folder that is included with the library download.
Copy the drawable-nodpi to your project's Objects/res folder and ensure that all files in that folder are set to read-only


The user can use the Manual and Auto Buttons to select LocationInputMode.
The Overlay for that LocationInputMode is added to the map - the Overlay for the not selected LocationInputMode is removed from the map.

Manual mode
===========

The user simply pans and zooms the map to select a location.

Auto mode
=========

MyLocationOverlay MyLocationEnabled and FollowLocationEnabled are set to True.
The map will automatically stay centered on the last GPS fix.

Each time a GPS fix is obtained, the code checks if FollowLocationEnabled is (still) True.
If FollowLocationEnabled is True and the current map zoom level is less than the OptimalZoomLevel then the map zooms in to the OptimalZoomLevel.

(If FollowLocationEnabled has been set to True and then the user pans or zooms the map then FollowLocationEnabled is automatically (internally) set to False - that is the default OSMDroid behavior).

I've made this into a 3 Activity example:

Activity 1 is just a button that starts Activity2 'GetLocation'.
When the user hits the Go Button in GetLocation, Activity3 'HandleLocation' is started and simply displays the selected location in a Label.

Here's the code for GetLocation:

B4X:
'Activity module
Sub Process_Globals
   Dim LocationInputMode As String
   Dim MapCenter As GeoPoint
   Dim ZoomLevel As Int
End Sub

Sub Globals
   Dim AutoButton, GoButton, ManualButton As Button
   Dim MapView1 As MapView
   Dim MyLocationOverlay1 As MyLocationOverlay
   Dim SimpleLocationOverlay1 As SimpleLocationOverlay
End Sub

Sub Activity_Create(FirstTime As Boolean)
   ManualButton.Initialize("AButton")
   ManualButton.Text="Manual"
   Activity.AddView(ManualButton, 0, 0, 33%x, 48dip)
   
   AutoButton.Initialize("AButton")
   AutoButton.Text="Auto"
   Activity.AddView(AutoButton, 33%x, 0, 33%x, 48dip)
   
   GoButton.Initialize("AButton")
   GoButton.Enabled=False
   GoButton.Text="Go"
   Activity.AddView(GoButton, 66%x, 0, 33%x, 48dip)
   
   MapView1.Initialize("MapView1")
   Activity.AddView(MapView1, 0, 48dip, 100%x, 100%y-48dip)
   
   MapView1.SetZoomEnabled(True)
   MapView1.SetMultiTouchEnabled(True)
   
   MyLocationOverlay1.Initialize(MapView1, "MyLocationOverlay1")
   SimpleLocationOverlay1.Initialize(MapView1)
   
   If FirstTime Then
      LocationInputMode=""
      
      '   use the new BoundingBox Initialize2 method to create a bounds of the UK
      Dim UKBounds As BoundingBox
      Dim NorthWest, SouthEast As GeoPoint
      NorthWest.Initialize(58.77, -13.8)
      SouthEast.Initialize(50.49, 3.4)
      UKBounds.Initialize2(NorthWest, SouthEast)
      
      '   i could have instead used the Initialize method:
      '   UKBounds.Initialize(58.77, -13.8, 50.49, 3.4)
      
      MapView1.FitMapToBoundingBox(UKBounds)
   Else
      MapView1.Zoom=ZoomLevel
      MapView1.SetCenter3(MapCenter)
   End If
   
   If LocationInputMode<>"" Then
      SetLocationInputMode(LocationInputMode)
   End If

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   MapCenter=MapView1.GetCenter
   ZoomLevel=MapView1.Zoom
   
   '   disable GPS tracking
   MyLocationOverlay1.MyLocationEnabled=False
End Sub

Sub AButton_Click
   Dim ClickedButton As Button
   ClickedButton=Sender
   If ClickedButton.Text="Go" Then
      MapCenter=MapView1.GetCenter
      StartActivity(HandleLocation)
   Else
      SetLocationInputMode(ClickedButton.Text)
   End If
End Sub

Sub MapView1_CenterChanged
   If LocationInputMode="Manual" Then
      SimpleLocationOverlay1.SetMyLocation3(MapView1.GetCenter)
   End If
End Sub

Sub MyLocationOverlay1_FollowLocationAutoDisabled
   AutoButton.Enabled=True
   ToastMessageShow("Click Auto to follow your GPS location", False)
End Sub

Sub MyLocationOverlay1_LocationChanged(NewLocation As Location, IsFirstFix As Boolean)
   If MyLocationOverlay1.FollowLocationEnabled Then
      Dim OptimalZoomLevel As Int
      OptimalZoomLevel=MapView1.GetMaxZoomLevel-2
      If MapView1.Zoom<OptimalZoomLevel Then
         MapView1.Zoom=OptimalZoomLevel
         ToastMessageShow("Zooming to your GPS location", False)
      End If
   End If
End Sub

Sub SetLocationInputMode(Mode As String)
   Select Mode
      Case "Manual"
         MapView1.RemoveOverlay(MyLocationOverlay1)
         MyLocationOverlay1.MyLocationEnabled=False
         AutoButton.Enabled=True
         
         MapView1.AddOverlay(SimpleLocationOverlay1)
         SimpleLocationOverlay1.SetMyLocation3(MapView1.GetCenter)
         ManualButton.Enabled=False
         ToastMessageShow("Pan & zoom the map to a location", False)
         LocationInputMode="Manual"
      Case "Auto"
         MapView1.RemoveOverlay(SimpleLocationOverlay1)
         ManualButton.Enabled=True
         
         MyLocationOverlay1.MyLocationEnabled=True
         MyLocationOverlay1.FollowLocationEnabled=True
         MapView1.AddOverlay(MyLocationOverlay1)
         AutoButton.Enabled=False
         ToastMessageShow("Following your GPS location", False)
         LocationInputMode="Auto"
   End Select
   If GoButton.Enabled=False Then
      GoButton.Enabled=True
   End If
End Sub

You can see in Activity_Create that i've used the new BoundingBox Initialize2 method and MapView FitMapToBoundingBox method to adjust the map center and zoom level to display the UK.

The new BoundingBox methods are described in the main library thread here: http://www.b4x.com/forum/additional...s/16309-osmdroid-mapview-b4a-2.html#post93130.

You will need the latest version 1.02 of OSMDroid to run this example.

Martin.
 

Attachments

  • 13- GetLocation.zip
    38.8 KB · Views: 1,070
Last edited:
Top