Android Tutorial Google Maps Android v2 tutorial

Discussion in 'Tutorials & Examples' started by Erel, Dec 18, 2012.

Thread Status:
Not open for further replies.
  1. ErickAsas

    ErickAsas Member Licensed User

    Thanks for pointing me in the right direction. I was using the wrong target.

    When I use cp.Target.Latitude and cp.Target.Longitude, nothing changes.

    When I use gmap.CameraPosition.Target.Latitude and gmap.CameraPosition.Target.Longitude, it now works fine.

    Thank again.:sign0142:
     
  2. hypergreatthing

    hypergreatthing Member Licensed User

    so i got the map to work. Question:
    I'm trying to plot out a lot of markers (around 10,000).
    While i can do this, is there some sort of scaling i can add so that they will only be displayed when zoomed in to a certain level?
    Thanks,
     
  3. rboeck

    rboeck Well-Known Member Licensed User

    You can use the event CameraChange from your MapFragment variable: As parameter you get CameraPosition, which show you the position of the camera and also your zoom level. I have a database with more than 5000 points and i want to try, if i should add the points at one time at the beginning or only for the current view...
    I think, we should post our experience for this in the next days.
    Greetings
    Reinhard
     
  4. hypergreatthing

    hypergreatthing Member Licensed User

    I'm thinking of a service to populate it, then a camera event to display the markers or not. I was trying to think of some way to only turn on the markers in a given area, but i don't think there's any functionality to do that.... Even forcing all the markers plotted to visible=false or true is sort of eluding me at the moment. I tried to populate all my markers on a activity and it was timing out. The tablet can run with 12k markers displaying at once, but zoomed out it runs at a crawl. Zoomed in it seems to display them fine, so i don't think it's a memory issue, it's just a drawing issue.
    Also, when you rotate the screen it redraws all the plots, not what i want to happen. I'll have to figure out why it's doing that and read up what gets triggered on a rotate.
     
  5. rboeck

    rboeck Well-Known Member Licensed User

    Hi,

    i want to report, how i it worked for me now: i have made it with an map_click event, when the user is interested, he clicks on the map and my app reads all locations from a database in an circle of 40 km. I think, its doable for the user, he can himself choose, where he want to see the labels.
    But: My system is useable, as long as the user doesnt change the zoom level very much. The second problem is, if the screen is full of markers, how to reset or remove them all in one action.
    Greetings
    Reinhard
     
  6. hypergreatthing

    hypergreatthing Member Licensed User

    Nevermind, the function addmarker returns marker, so i can add them and then modify their visibility and add them to a list.
     
    Last edited: Mar 12, 2013
  7. warwound

    warwound Expert Licensed User

    GoogleMapsExtras version 1.20 adds support for the InfoWindowAdapter enabling you to customise the appearance of the info window.

    The InfoWindowAdapter raises GetInfoContents and GetInfoWindow events, your event handling Sub must return a View or Null to the library.
    GetInfoContents allows you to use the default info window but replace the info window content with your own View.
    GetInfoWindow allows you to completely replace the default info window with your own View.
    If either of these Subs return Null then the default content or info window will be used.

    First an example that shows using the GetInfoContents event:

    Code:
    Sub Process_Globals

    End Sub

    Sub Globals
       
    Dim InfoWindowLabel As Label
        
    Dim MapFragment1 As MapFragment
       
    Dim Markers As Map
        
    Dim GoogleMap1 As GoogleMap
        
    Dim MapPanel As Panel
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")
        
    If MapFragment1.IsGooglePlayServicesAvailable = False Then
            
    ToastMessageShow("Google Play services not available."True)
        
    Else
            MapFragment1.Initialize(
    "MapFragment1", MapPanel)
        
    End If 
    End Sub

    Sub MapFragment1_Ready
        
    Log("MapFragment1_Ready")
        GoogleMap1 = MapFragment1.GetMap
        
    If GoogleMap1.IsInitialized = False Then
            
    ToastMessageShow("Error initializing map."True)
        
    Else
          
    Dim GoogleMapsExtras1 As GoogleMapsExtras
          
    Dim InfoWindowAdapter1 As InfoWindowAdapter
          
          InfoWindowAdapter1.Initialize(
    "InfoWindowAdapter1")
          GoogleMapsExtras1.SetInfoWindowAdapter(GoogleMap1, InfoWindowAdapter1)
          
          InfoWindowLabel.Initialize(
    "")
          InfoWindowLabel.Color=
    Colors.Red
          InfoWindowLabel.TextColor=
    Colors.White
          Markers.Initialize
          
          
    Dim Marker1 As Marker
            Marker1=GoogleMap1.AddMarker(
    52.756190.3980"Home Sweet Home")
          Marker1.Snippet=
    "Home is where the heart is!"
          Markers.Put(Marker1, Marker1)
          
          
    Dim Marker1 As Marker
            Marker1=GoogleMap1.AddMarker(
    52.935140.4829"Hunstanton")
          Marker1.Snippet=
    "A charming seaside town. Popular with the tourists."
          Markers.Put(Marker1, Marker1)
          
            
    Dim CameraPosition1 As CameraPosition
            CameraPosition1.Initialize(
    52.756190.39808)
            GoogleMap1.AnimateCamera(CameraPosition1)
        
    End If
    End Sub

    Sub InfoWindowAdapter1_GetInfoContents(Marker1 As MarkerAs View
       
    '   the default InfoContent will be used if this event Sub is not defined or if it returns Null
       Log("InfoWindowAdapter1_GetInfoContents")
       
       
    '   re-using the InfoWindowLabel works in GetInfoContents
       
       InfoWindowLabel.Text=Marker1.Title&
    CRLF&Marker1.Snippet
       
    Return InfoWindowLabel
    End Sub
    I add a couple of markers to the map and a click on a marker shows the default info window with a rather unimpressive red Label containing the text that is the marker title and description.

    Note that this Label is declared once in Globals and re-used each time the library requests a View for the info window content.

    This next example shows how to use the GetInfoWindow event to completely replace the default info window with your own View.

    Code:
    Sub Process_Globals

    End Sub

    Sub Globals
        
    Dim MapFragment1 As MapFragment
       
    Dim Markers As Map
        
    Dim GoogleMap1 As GoogleMap
        
    Dim MapPanel As Panel
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")
        
    If MapFragment1.IsGooglePlayServicesAvailable = False Then
            
    ToastMessageShow("Google Play services not available."True)
        
    Else
            MapFragment1.Initialize(
    "MapFragment1", MapPanel)
        
    End If 
    End Sub

    Sub MapFragment1_Ready
        
    Log("MapFragment1_Ready")
        GoogleMap1 = MapFragment1.GetMap
        
    If GoogleMap1.IsInitialized = False Then
            
    ToastMessageShow("Error initializing map."True)
        
    Else
          
    Dim GoogleMapsExtras1 As GoogleMapsExtras
          
    Dim InfoWindowAdapter1 As InfoWindowAdapter
          
          InfoWindowAdapter1.Initialize(
    "InfoWindowAdapter1")
          GoogleMapsExtras1.SetInfoWindowAdapter(GoogleMap1, InfoWindowAdapter1)
          
          Markers.Initialize
          
          
    Dim Marker1 As Marker
            Marker1=GoogleMap1.AddMarker(
    52.756190.3980"Home Sweet Home")
          Marker1.Snippet=
    "Home is where the heart is!"
          Markers.Put(Marker1, Marker1)
          
          
    Dim Marker1 As Marker
            Marker1=GoogleMap1.AddMarker(
    52.935140.4829"Hunstanton")
          Marker1.Snippet=
    "A charming seaside town. Popular with the tourists."
          Markers.Put(Marker1, Marker1)
          
            
    Dim CameraPosition1 As CameraPosition
            CameraPosition1.Initialize(
    52.756190.39808)
            GoogleMap1.AnimateCamera(CameraPosition1)
        
    End If
    End Sub

    Sub InfoWindowAdapter1_GetInfoWindow(Marker1 As MarkerAs View
       
    '   the default InfoWindow will be used if this event Sub is not defined or if it returns Null
       Log("InfoWindowAdapter1_GetInfoWindow")
       
       
    Dim InfoWindowLabel As Label
       InfoWindowLabel.Initialize(
    "")
       InfoWindowLabel.Color=
    Colors.Red
       InfoWindowLabel.TextColor=
    Colors.White
       
       InfoWindowLabel.Text=Marker1.Title&
    CRLF&Marker1.Snippet
       
    Return InfoWindowLabel
    End Sub
    A click on a marker now shows just the red Label as in the previous example - no info window.

    If you try to re-use a View for the info window it will work the first time GetInfoWindow is called, after that your activity will crash - You cannot re-use a View with GetInfoWindow, you must create a new View each time it is called.

    Neither of these examples are visually inspiring!
    You will need to get creative yourself if you want to improve on the default info window and it's content.
    You're not limited to using a Label for these Views, any View can in theory be used.

    Both examples are attached.

    Martin.
     

    Attached Files:

    Last edited: Mar 13, 2013
  8. hypergreatthing

    hypergreatthing Member Licensed User

    So question:
    is VisibleRegion implemented?
    Thanks,
     
  9. warwound

    warwound Expert Licensed User

    Not yet!
    I've implemented the Projection and VisibleRegion objects and updated GoogleMapsExtras with a GetProjection method:

    Projection
    Methods:
    • FromScreenLocation (Point1 As Point) As LatLngWrapper
      Returns the geographic location that corresponds to a screen location.
      This method is of no real use until Point object is wrapped and can be passed as a parameter.
    • GetVisibleRegion As VisibleRegion
      Gets a projection of the viewing frustum for converting between screen coordinates and geo-latitude/longitude coordinates.
    • IsInitialized As Boolean
    • ToScreenLocation (LatLng1 As LatLng) As Point
      Returns a screen location that corresponds to a geographical coordinate.
      This method is of no real use until Point object is wrapped and the method updated to return a wrapped Object.

    VisibleRegion
    Methods:
    • Initialize (NearLeft As LatLng, NearRight As LatLng, FarLeft As LatLng, FarRight As LatLng, LatLngBounds1 As LatLngBounds)
      Creates a new VisibleRegion given the four corners of the camera.
    • IsInitialized As Boolean
    Properties:
    • FarLeft As LatLngWrapper [read only]
    • FarRight As LatLngWrapper [read only]
    • LatLngBounds As LatLngBounds [read only]
    • NearLeft As LatLngWrapper [read only]
    • NearRight As LatLngWrapper [read only]

    GetProjection (GoogleMap1 As GoogleMap) As Projection
    Returns a Projection object that you can use to convert between screen coordinates and latitude/longitude coordinates.

    So you can create a VisibleRegion and also get one from the Projection object.
    But what use is a Visible Region?
    Is it used to set the map camera position? I can't find any documentation or examples that actually shows it in use.

    If you can give me an idea of what you want to use VisibleRegion for i'll complete this update.

    Martin.
     
  10. hypergreatthing

    hypergreatthing Member Licensed User

    I have over 10k markers on my gmap. Displaying them all zoomed out is not appropriate. There is no scaling built into markers that says something like, only display when zoomed in at greater than zoom 13 so i'm building my own scaling.
    The idea is to populate two maps (the container called map like a list, not a gmap) with the markers that i'm displaying and setting the marker.visible=false when initalizing. Then when the user zooms into zoom>12 or 13, use the visibleregion boundaries and do a query to my database of points, sets only those inside the visibleregion to visible=true.
    I said i'm using two maps. One map contains all the list of all my markers where the key is a unique key in the database that contains my points. The second map is a list of all markers that are currently plotted. I use that to keep track of which ones are turned on so i can iterate through that list when i need to turn off visibility outside the current camera bounds.
    This is all processed by a service so when initializing or drawing the markers, it doesn't lock up the app/activity.
    I don't think the number of markers in memory decreases performance, but when zooming with anything like 1000+ markers displayed all at once, the gmap seems to redraw each one individually, making performance really slow.
    I would love to have some sort of built in function that says only display when camera zoom > X for each marker, but that doesn't look like a function of google maps for android api. I think it is for google maps v3 api.
     
  11. warwound

    warwound Expert Licensed User

    It's a real shame that Google made so many of the classes in the new Android v2 library final - they cannot then be extended to enhance functionality.
    That more or less means that you have the built in Android v2 map objects and that's that - not like the original Android v1 library where you were free to extend the base objects and add the functionality you required.

    Anyway - mini rant over!

    So you want to get the map bounds and be able to work out which markers in your database are within the visble map bounds?

    You should be able to do that with the update as it is:

    Code:
    Sub Process_Globals
    End Sub

    Sub Globals
        
    Dim MapFragment1 As MapFragment
        
    Dim GoogleMap1 As GoogleMap
       
    Dim GoogleMapsExtras1 As GoogleMapsExtras
        
    Dim MapPanel As Panel
       
    Dim Projection1 As Projection
       
    Dim VisibleRegion1 As VisibleRegion
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")
        
    If MapFragment1.IsGooglePlayServicesAvailable = False Then
            
    ToastMessageShow("Google Play services not available."True)
        
    Else
            MapFragment1.Initialize(
    "MapFragment1", MapPanel)
        
    End If 
    End Sub

    Sub MapFragment1_Ready
        
    Log("MapFragment1_Ready")
        GoogleMap1 = MapFragment1.GetMap
        
    If GoogleMap1.IsInitialized = False Then
            
    ToastMessageShow("Error initializing map."True)
        
    Else
            
    Dim CameraPosition1 As CameraPosition
            CameraPosition1.Initialize(
    52.756190.39808)
            GoogleMap1.AnimateCamera(CameraPosition1)
        
    End If
    End Sub

    Sub MapFragment1_CameraChange (Position As CameraPosition)
       
    Log("MapFragment1_CameraChange")
       Projection1=GoogleMapsExtras1.GetProjection(GoogleMap1)
       VisibleRegion1=Projection1.GetVisibleRegion
       
    Log(VisibleRegion1.LatLngBounds)
    End Sub
    Remember that a LatLngBounds object has a Contains method which should be useful to work out which LatLng objects are within the LatLngBounds.

    Example code and (beta) library update attached.
    Can you post again with your results? Confirm everything works as expected and i'll get the library update uploaded to it's main thread.

    Martin.
     

    Attached Files:

    Last edited: Mar 15, 2013
  12. hypergreatthing

    hypergreatthing Member Licensed User

    This works great. Thank you so much. The VisibleRegion is working as intended, i'm able to change the visibility of the markers within the region to on when the camera is pointing at the location. Since i'm dealing with a subset of my 10k+ markers, performance is good. My map solution is working well, my plottedmarkers map is setting visibility of the markers to false when they're outside of the VisibleRegion. I might create a generic class for this and add it to this thread at a later time.
    hmm, something minor but i noticed that when i'm calling addmarker, even though i'm immediately setting it to visible=false, it flashes on the screen. Any way to create a addmarker function that takes value of marker so i can initialize it before i add it to the map?
    Also off topic, but since i'm adding a lot of markers to the map, is there a way to tell the OS that during pause and resume to not clear out the variables? Should i put them in a service that's sticky or whatnot? Rotations take a while, i'm trying to figure out a way where it's a lot faster.
    Thanks,
     
  13. warwound

    warwound Expert Licensed User

    The way that Erel created the b4a GoogleMaps library did not expose the MarkerOptions object and this is the object you'd need to use to create a Marker that is initially not visible.

    So i've now partly wrapped the MarkerOptions object and added a new method to GoogleMapsExtras AddMarker(MarkerOptions1 As MarkerOptions) As Marker.

    Have a look at this example code:

    Code:
    Sub Process_Globals

    End Sub

    Sub Globals
        
    Dim MapFragment1 As MapFragment
        
    Dim GoogleMap1 As GoogleMap
       
    Dim GoogleMapsExtras1 As GoogleMapsExtras
        
    Dim MapPanel As Panel
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")
        
    If MapFragment1.IsGooglePlayServicesAvailable = False Then
            
    ToastMessageShow("Google Play services not available."True)
        
    Else
            MapFragment1.Initialize(
    "MapFragment1", MapPanel)
        
    End If 
    End Sub

    Sub MapFragment1_Ready
        
    Log("MapFragment1_Ready")
        GoogleMap1 = MapFragment1.GetMap
        
    If GoogleMap1.IsInitialized = False Then
            
    ToastMessageShow("Error initializing map."True)
        
    Else
          
    '   use the new MarkerOptions method to create and add a Marker to the map
          
          
    Dim MarkerOptions1 As MarkerOptions
          MarkerOptions1.Initialize
          
          MarkerOptions1.Position2(
    52.756190.3980).Snippet("Home is where the heart is").Title("Home Sweet Home").Visible(True)
          
    Dim Marker1 As Marker=GoogleMapsExtras1.AddMarker(GoogleMap1, MarkerOptions1)
          
            
    Dim CameraPosition1 As CameraPosition
            CameraPosition1.Initialize(
    52.756190.39806)
            GoogleMap1.AnimateCamera(CameraPosition1)
        
    End If
    End Sub
    MarkerOptions
    Methods:
    • Anchor (U As Float, V As Float) As MarkerOptions
    • Draggable (Draggable As Boolean) As MarkerOptions
    • Initialize
    • IsInitialized As Boolean
    • Position (LatLng1 As LatLng) As MarkerOptions
    • Position2 (Latitude As Double, Longitude As Double) As MarkerOptions
    • Snippet (Snippet As String) As MarkerOptions
    • Title (Title As String) As MarkerOptions
    • Visible (Visible As Boolean) As MarkerOptions

    I've not fully wrapped the MarkerOptions object, there are various other methods that can also be wrapped, take a look: https://developers.google.com/maps/...m/google/android/gms/maps/model/MarkerOptions.

    Code and beta library files attached - i'll complete the MarkerOptions object hopefully tomorrow and get it uploaded to the GoogleMapsExtras thread.

    When the device orientation changes you have no way to tell the activity not to destroy all of it's objects and variables - that's the way android works.

    You could keep references as process global objects - not sure about a sticky service but i guess that's another way to keep a reference to objects you create but don't want destroyed when the orientation changes.

    Note that you should not keep a reference to a Marker - a Marker is an Activity object and should be destroyed when the activity is destroyed.
    Don't try to keep a process global reference to a Marker - there's no point, you can't add a Marker to the map, BUT you can keep a process global reference to a MarkerOptions object.

    So create a MarkerOptions object for each of your many markers, and keep each MarkerOptions object as a process global (or try and use a service), then on orientation change you can re-create new Markers from the (already created) MarkerOptions objects.

    Martin.
     

    Attached Files:

    Last edited: Mar 15, 2013
  14. hypergreatthing

    hypergreatthing Member Licensed User

    hmmm.... well if there's no way to tell the OS to make a variable persistent, then maybe instead of trying to manage everything in memory with the visible flag, it might be easier to just create the markers as needed and get rid of them once they're off screen. It's just that red flags in my own head get thrown up when i'm creating, deleting, then possibly recreating the same object over and over. I'm not quite sure how good garbage collection is and i don't want my app to look like it has a memory leak, hence trying to create everything once in memory and managing it using the visible flag.
    And thanks warwound, your help has been invaluable and much appreciated.
     
  15. electronik54

    electronik54 Member Licensed User

    :sign0085: :sign0104:
    hi....
    i am using GMaps to display few location. locations are selected fro listview and a layout is called which displays the location on the map.
    The problem is it only works for the first location for second and so on locations the map would freeze at latitude = longitude = 0.00. zoom function wont work too.
    is there anything so that i can reset the map?
     
  16. warwound

    warwound Expert Licensed User

    The Google Maps Android API v2 library was updated Feb 2013:

    https://developers.google.com/maps/documentation/android/releases#february_2013

    Many bug fixes and a few new classes.
    Among the updates you will see:

    The B4A GoogleMaps library ought to be updated and this permission added i think?

    Martin.
     
  17. warwound

    warwound Expert Licensed User

    Take a look at the Feb 2013 update from Google: https://developers.google.com/maps/documentation/android/releases#february_2013.

    It may be worthwhile for you to update your SDK to the latest version.
    After updating your SDK be sure that you also copy the new (updated) google-play-services.jar from your SDK folder to your b4a additional libraries folder, overwriting the old version.

    Martin.
     
  18. warwound

    warwound Expert Licensed User

    GoogleMapsExtras version 1.31 adds support for the new Circle and CircleOptions classes.

    Here's a simple example:

    Code:
    Sub Process_Globals

    End Sub

    Sub Globals
        
    Dim MapFragment1 As MapFragment
        
    Dim GoogleMap1 As GoogleMap
       
    Dim GoogleMapsExtras1 As GoogleMapsExtras
        
    Dim MapPanel As Panel
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")
        
    If MapFragment1.IsGooglePlayServicesAvailable = False Then
            
    ToastMessageShow("Google Play services not available."True)
        
    Else
            MapFragment1.Initialize(
    "MapFragment1", MapPanel)
        
    End If 
    End Sub

    Sub MapFragment1_Ready
        
    Log("MapFragment1_Ready")
        GoogleMap1 = MapFragment1.GetMap
        
    If GoogleMap1.IsInitialized = False Then
            
    ToastMessageShow("Error initializing map."True)
        
    Else
          
    Dim CircleOptions1 As CircleOptions
          CircleOptions1.Initialize
          
          CircleOptions1.Center2(
    52.756190.3980).FillColor(Colors.ARGB(12819200)).Radius(500).StrokeColor(Colors.Black).StrokeWidth(2)
          
          
    Dim Circle1 As Circle=GoogleMapsExtras1.AddCircle(GoogleMap1, CircleOptions1)
          
            
    Dim CameraPosition1 As CameraPosition
            CameraPosition1.Initialize(
    52.756190.398014)
            GoogleMap1.AnimateCamera(CameraPosition1)
        
    End If
    End Sub
    Martin.
     

    Attached Files:

  19. grguido

    grguido New Member Licensed User

    mapFragment: missing library reference

    Sorry for my maybe stupid question and for my poor English, but I don't understand what to do at step 2.5 of this tutorial. I installed Google Play Service, I recived api key from google api console, I update the manifest and so on for all other steps, but when I run the exemple in the tutorial I recive this error:"Error description: Unknown type: mapfragment". Missing reference to library. How can I reference this library? Can anyone help me?
     
  20. Erel

    Erel Administrator Staff Member Licensed User

    Have you checked GoogleMaps in the libraries tab (right side of the IDE)?
     
Thread Status:
Not open for further replies.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice