B4J Question JGooglemaps JobDone

atiaust

Active Member
Licensed User
Longtime User
Hi All,

I am using jGoogleMAps to get the Lat Long position of properties with the street address.
This works well but there is a slight delay while Google finds the property and returns the LatLong which is fine for a stand alone app.

I have used the same code in a separate Code Module that can be accessed from other modules in my program. My problem is that due to the Google delay the Code Module returns back to the calling module before the LatLong is obtained.

How can I delay the return from the code module until the LatLong is received or maybe use something like jRandomAccessFile to collect the LatLong and advise when recieved?

B4X:
'Get the address Geo-Code for Google Maps
'Requires Street No as string, Street Name as string, Suburb as string, State as string - returns Lat/Long as string
Sub getGeoCode(streetno As String, street As String, suburb As String, state As String) As String
'    https://maps.googleapis.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY
'   
    parser.Initialize
    Dim Googlekey As String = "AIzaxxxxxxxxxxxxxxxxxxxxxxxxxxCE"    '(my) google api key
    Dim job As HttpJob
    Dim poststring As String
'   
'    poststring = "address=1+Short+Street+South,+Sydney,+NSW&Key=" &Googlekey
    street = street.Replace(",","+")
    street = street.Replace(" ","+")
    suburb = suburb.Replace(" ","+")
'    build string from input text fields. Trim to get rid of crap
        poststring = "address="&streetno.Trim&"+"&street.Trim&",+"&suburb&",+"&state&"&Key="
        poststring = poststring & Googlekey
        LogDebug(poststring)
'       
    job.Initialize("LatLong",Me)
    job.PostString("https://maps.googleapis.com/maps/api/geocode/xml?" & poststring, "")
    'gmap.
'   maybe loop until latlong is returned with a value - this is a time delay
   
    Return latlong
End Sub

Sub jobDone(job As HttpJob)
    Dim in As InputStream
    in = job.GetInputStream
'   
    parser.Parse(in,"Parser")
    LogDebug("in = "&in&" Lat = "&lat&" Long = "&lng)
'    lblLat.Text = lat
'    lblLng.Text = lng
'    gmap.AddMarker(lat,lng,"1 Short St")
'    gmap.MapType = gmap.MAP_TYPE_NORMAL
'    Dim cp As CameraPosition
'    cp.Initialize(lat, lng, 12)    'lat, long, zoom level
'    gmap.MoveCamera(cp)
'
'    'LogDebug("After Parser")       
    If job.Success Then
        Select job.JobName
            Case "LatLong"
                Main.latlong = lat & "," & lng
                LogDebug("job.getstring = "&Main.latlong)
'                txtReply.Text = job.GetString
                latlong = lat & "," & lng
            'parser.
'    break the string apart and get the lat/longs.....
            Case "ZERO_RESULTS"
                LogDebug($"No Results"$)
            Case Else
                LogDebug($"Error:${job.GetString}"$)
                LogDebug($"No Results"$)           
        End Select
    End If
'   
End Sub

Sub parser_StartElement(Uri As String, Name As String, Attributes As Attributes )                'Text As String
    'LogDebug("parser begin")
    If Name = "location" Then
        'LogDebug("Location at start")
    End If
End Sub

Sub parser_EndElement(Uri As String, Name As String, Text As StringBuilder)
    If parser.Parents.IndexOf("location") > -1 Then
        If Name = "lat" Then
            lat = Text.ToString
        End If
        If Name = "lng" Then
            lng = Text.ToString
        End If   
        LogDebug("Location at end")
    End If
    'LogDebug("parser end")
End Sub

Hope this is somewhat clear.

Thanks
 

jmon

Well-Known Member
Licensed User
Longtime User
You should do that with CallSub*

https://www.b4x.com/android/forum/pages/results/?query=callsub
Method_636.png
CallSub (Component As Object, Sub As String) As Object

Calls the given sub. CallSub can be used to call a sub which belongs to a different module.
However the sub will only be called if the other module is not paused. In that case an empty string will be returned.
You can use IsPaused to test whether a module is paused.
This means that one activity cannot call a sub of a different activity. As the other activity will be paused for sure.
CallSub allows an activity to call a service sub or a service to call an activity sub.
Note that it is not possible to call subs of code modules.
CallSub can also be used to call subs in the current module. Pass Me as the component in that case.
Example:
CallSub(Main, "RefreshData")

Basically, when you get the Lat& long, you notify the other modules that you got the answer:
B4X:
'in you google map code module
CallSub2(Main, "Gmap_LatLongReceived", MyLatLong)
B4X:
'in your other module
Sub Gmap_LatLongReceived(LatLong As String)
    log(LatLong)
End sub

you can see from other libraries how they store the Module and EventName, check out the source of that library:
https://www.b4x.com/android/forum/threads/transitions-and-animations-libraries.43136/
 
Upvote 0

atiaust

Active Member
Licensed User
Longtime User
Thanks jmon for you answer but I am a little confused.

In the description above it states "Note that it is not possible to call subs of code modules."

In my program I call the getGeoCode sub in the GoogleMap code module from the main module using
B4X:
txtLocation.text = GoogleMap.getGeoCode(txtStreetNo.Text,TxtStreetName.Text,suburb,state)

The GoogleMap module is the code in the first post. Due to the google map processing delay the string returned to "txtLocation.text" is empty.

I think you are saying to call back to a sub in the main module from the GoogleMap module once the location is received by the GoogleMap Module because the original call will have already returned to the main module without the location?

This sub will be called from the jobDone sub in the GoogleMap sub.
 
Upvote 0

jmon

Well-Known Member
Licensed User
Longtime User
In the description above it states "Note that it is not possible to call subs of code modules."
Maybe the description is faulty, because it works. I've attached a little example that demonstrates how you can call subs from one module to the other
 

Attachments

  • CallSubExample.zip
    2.5 KB · Views: 119
Upvote 0

jmon

Well-Known Member
Licensed User
Longtime User
As Google Geocode will return a value in the future, you need to change your code to update WHEN you get the geocode value.

The correct process is like this:
  1. Send a geocode request
  2. Receive the value
  3. callSub the updating sub
  4. update the text with the value (txtLocation.text = MyValue)
Right now what happens in your code is:
  1. update the text with the value (which doesn't exist yet).
  2. Send a geocode request
  3. do nothing with the received value
your txtLocation needs to be updated only when the geocode is done.
 
Upvote 0
Top