Android Question Gps in second plain

jota1010

Member
Licensed User
Longtime User
Good morning, afternoon or evening, what happens is that I made an application where every 10 minutes I registar the GPS coordinates generated in a database, the problem is that if I do not initialize at each activity the code of GPS, and not sure if would generate conflicts, more forms to access the database.
That possibility exists within the application to handle any type of secondary thread or application in the background to the main, to do this without problems.

Thank you very much and best regards,
Bayron.
 

Harris

Expert
Licensed User
Longtime User
You could place the GPS routine in a service.


Below is a service module I wrote for one of my apps...
It uses many vars from my code module (DefCM).

It can:
Accumulate distance travelled using GPS
Write GPS string to a file for each new record.
Get the location (city, state) from my DB with lookup of lat/lon.
Start the application at first boot of device.

Take what you can use from it...



B4X:
Type=Service
Version=2.02
StartAtBoot=True
@EndOfDesignText@
'
' ***************************************************************************************************************
' Service module for GPS Stats (can be used by other modules) and GPS file recording ( Happens from within this service automatically)
' ***************************************************************************************************************
'
' This is like an automatic Accident Recording Buffer (file). 
'
' Proposed Usage:
' If you are driving (or stopped), GPS data is being constantly recorded.  Why????
'    Say you are sitting at a Stop Light and somebody rear ends you.  What is your defence?
'    Say you are driving at the posted speed limit (or below) AND suddenly you are involved in an incident.  What Is your defence?
'    Say either of the above happened to you.  How do you (currently) preserve this valuable data?  SHUT THE DEVICE OFF!!!!! (it stops recording any further data)
'    From Experince, relying on the user to preserve this valuable info (in this time of distress) can not be relied upon.  An automatic process must be found.
'    (ie longer accident buffer - 24 hours? - Decel or Acel > or < than x value?) 
'
' Credits:
' STOLEN from various contributors of B4A.  Without the combined knowledge and experience, I would have (almost - OK never)) never figured this out..
' Thanks all.... you are truely brilliant
' It's never perfect - HELP!!!!! where you can...
'
'  Current defaults are meteric (SI) - convert where required.
'

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim GPSservice1 As GPS        ' delcare a GPS
    Dim count As Int              ' a counter for various purposes 
    Dim GPSStarted As Boolean    ' is this service running?
   
    Type TypeLoc (fDate As Long, fAccuracy As Float, fAccuracyValid As Boolean, fAltitude As Double, fAltitudeValid As Boolean, fBearing As Float, fBearingValid As Boolean, fLatitude As Double, fLongitude As Double, fSpeed As Float, fSpeedValid As Boolean, fTime As Long, fValidSats As Int,fDistance As Double)
        '  This structure captures all GPS that is published from the Location object (GPS_LocationChanged) - other than a few
   
    Dim gLoc            As TypeLoc      ' DIM - create a NEW TypeLoc
    Dim fSats          As String      ' used and all GPS sats in view
    Dim fvSats          As Int          ' sats that are "vaild"
   
    Dim fWriter        As TextWriter  ' declare a file object
    Dim fGPSstr        As String      ' declare a string to be written to the file
    Dim fGPSFileName    As String      ' what file shall we write to? (there are 2 - GPSrecords and GPSrecords1)
    Dim GPSTick        As String      ' this shows on any form that the service is running (by blinking the * )
   
    Dim latstart,latstop,lonstart,lonstop As Double    ' used to determine distance travelled
    Dim GPSFileSize    As Long                        ' what is the max file size before we write to the next file?
   
    Dim DEGREES_TO_RADIANS As Double    : DEGREES_TO_RADIANS = (cPI / 180.0)
    Dim EARTH_RADIUS    As Double
    '    EARTH_RADIUS = 3959        ' miles
        EARTH_RADIUS = 6371        ' km            ' used as default - convert where required for NON SI reporting (ie. USA)
       
    Dim Distance, SpdMoreThan, M_K As Double
    Dim MyDir As String
    Dim GPS_Rec As Boolean
'    Dim Bootup As Boolean : Bootup = True

   
    Dim fCurSpd As Float
   
    M_K = 3.6  ' kmh
'    M_K = 2.23693629  ' mph

End Sub
Sub Service_Create
 
    ' this section is "only" called when THIS service is not running (has never been started or has been killed by OS)
    ' repeated calls to "StartServiceAt" will NOT invoke (Service_Create) this method if service is currently running - (a good thing)
    DefCM.Bootup = True
    GPS_Rec = True
   
    GPSservice1.Initialize("GPS")
    gLoc.Initialize        ' init structure
   
    fvSats      = 0        ' valid sats = 0 when starting
    SpdMoreThan = 2.0      ' the speed at which distance shall accumulate (reduces wandering GPS from acruring distance) - set higher or lower as needed for your situation
    GPSFileSize = 500000    ' byte size of file until it is saved and the rotating file begins (GPSrecord and GPSrecord1.txt)           
   
    GPSStarted  = False    ' GPS system has not been started at this point -  we are just now starting it
    Distance = 0.0          'CodeMod.Odom ' Init distance from last saved value
    MyDir = File.DirDefaultExternal  '&"/aMHW/"
   
    ' Note - start at boot is set ON.  If your device is ON, GPS data is being recorded.  PLUG YOUR DEVICE INTO A CAR CHARGER!!!
   
    If GPSservice1.GPSEnabled = False Then
        ToastMessageShow("Please enable the GPS device.", True)
        StartActivity(GPSservice1.LocationSettingsIntent) 'Will open the relevant settings screen.
    End If

    'ToastMessageShow("  Creating GPS Service - Setting up records and files...    ", True)
    '  Shows that service has started -  caveat - if you can unlock your device early enough after booting.
    '  Otherwise - If you try - "Settings - Applications - Running Services"  shows one process and one service for the app you included this module
   

End Sub


Sub Service_Start (StartingIntent As Intent)
 
  'Return  ' remove after testing
 
 
  StartServiceAt( "", DateTime.Now + 60 * 1000, True) ' make sure service is always running (even when sleeping) - every 60 seconds
                                                    ' device must be always be charging or battery will die soon (set last param to false to preserve battery)
  If GPSStarted = False Then
  ' GPSservice1.Start(30000,0)  ' used when stopped
    DefCM.LoadGeoDB
    GPSservice1.Start(0,0)    ' use when driving
   
    'Listen to GPS with no filters.
    count = 0
    GPSStarted = True
    fCurSpd = 0.0
   
    ToastMessageShow("Starting GPS Service - Connect Device to a Charger", True)  ' always show that service has started
    InitGPSFileName        ' determine which file to start with (1 or 2)
'    CodeMod.ReadDef
    If DefCM.Bootup = True Then
      'ToastMessageShow("Launching Application at Bootup", True)  ' always show that service has started
      StartActivity(Main)
    Else
      'ToastMessageShow("Start Application at Bootup Disabled", True)  ' always show that service has started
    End If 
  Else
    Log(" GPS Service was already running - no need to init again ")
    'If count = 100 Then
        DefCM.FindNearest ' find nearest location from service mod
        'DefCM.TM(" Nearest Location: "&DefCM.CurrLoc)
    'End If

  End If
  '  MIDNITE TIME STAMP
  ' determine if a midnight record needs to be recorded - need a time stamp when over midnite - checks every minute...
  ' if midnite has elapsed, what was the last status we were in
  ' record new stat once based on last stat - stamped at midnite and carry on
  ' check if last stat date is one day older - if so - write new record based on last stat date -
' 
  DefCM.CheckForMidnite

 
End Sub


Sub GPS_LocationChanged (Location1 As Location)
    Dim dist As Double
    Dim d As String
   
    dist = 0.0
   
    count = count + 1
   
    gLoc.fDate          = DateTime.Now                  ' populate the structure for file writing and other modules that may require it
    gLoc.fAccuracy      = Location1.Accuracy
    gLoc.fAccuracyValid  = Location1.AccuracyValid
    gLoc.fAltitude      = Location1.Altitude
    gLoc.fBearing        = Location1.Bearing
    gLoc.fBearingValid  = Location1.BearingValid        ' note that "BearingTo" and others are not included here since they need params we do not have at this point
    gLoc.fLatitude      = Location1.Latitude           
    gLoc.fLongitude      = Location1.Longitude
    gLoc.fSpeed          = Location1.Speed
    gLoc.fSpeedValid    = Location1.SpeedValid
    gLoc.fTime          = Location1.Time
    gLoc.fValidSats      = fvSats
   
   
    If count = 101 Then
      count = 1          ' this can be used for a progress bar to show service is running (what the hell...)
    End If

    '**************************  Distance Recording Section Below *********************************************
    '  ***  distance is NOT stored in the file.  It's purpose is to keep a running odometer of distance travelled.
    '  ***  use as you see fit in your application
    '  ***  store the last value recorded and start from there when your app restarts (Distance = mylastvalue)
    ' ***********************************************************************************************************
   
    latstop = gLoc.fLatitude
    lonstop = gLoc.fLongitude
   
  '  Log(" GPS Service Lat - Lon: " &latstop&"    "&lonstop)
  '  Log(" GPS Service Fix Time: " &DateTime.Date(gLoc.fTime)&"  "&DateTime.Time(gLoc.fTime))
   

   
    If latstart = 0 AND lonstart = 0 Then
        latstart = latstop
        lonstart = lonstop
    End If
   
    If gLoc.fAccuracyValid = True Then
      If (gLoc.fSpeed * M_K) > SpdMoreThan Then  ' when speed is valid and more than specified value (SpdMoreThan) - accumulate distance
        dist = GetDistance(latstart,lonstart,latstop,lonstop)
        d = dist
       
       
        If (IsNumber(d) = False) Then
            'ToastMessageShow(" Dist is NAN",True)
            Distance =  Distance + 0
        Else
            'Distance =  Distance + dist
            Distance =  dist              ' used when odom is setup by user - add to that
            DefCM.CurrOdom = DefCM.CurrOdom + Distance
        End If       
      Else
        Distance = 0.0
     
      End If
     
     
      fCurSpd = gLoc.fSpeed * 3.6  ' speed in kph

    End If
   
    latstart = latstop  ' set last known location for next distance (how far did we travel from last point until this point? (usually 1 second ago) )
    lonstart = lonstop
   
    gLoc.fDistance  = Distance

   
    fGPSstr = DateTime.Date(gLoc.fDate)&" "&DateTime.Time(gLoc.fDate)&","&gLoc.fDate&","&gLoc.fAccuracy&","&gLoc.fAccuracyValid&","&gLoc.fAltitude&","&NumberFormat2(gLoc.fBearing,1,1,1,False)&","&gLoc.fBearingValid&","&NumberFormat2(gLoc.fLatitude,1,6,1,False)&","&NumberFormat2(gLoc.fLongitude,1,6,1,False)&","&NumberFormat2(gLoc.fSpeed * 3.6,1,1,1,False)&","&gLoc.fSpeedValid&","&gLoc.fTime&","&gLoc.fValidSats&","&NumberFormat2(gLoc.fDistance,1,4,1,False)
    '  a comma deliminated string (cvs) that is stored in a file - parse later to reconstruct what happened during the record session
    '  set the max file size (GPSFileSize) to a value based on how much data you need to retain.
    If GPS_Rec = True Then
      If (gLoc.fSpeed * M_K) > SpdMoreThan Then  ' when speed is valid and more than specified value (SpdMoreThan) - record data
          RecordGPSFile  ' store fGPSstr to the file
      Else
          If count = 2 Then                        ' if speed is less than x - record a sample every 100 seconds
            RecordGPSFile 
          End If     
      End If
    End If
   
   
   
    If count Mod 2 = 0 Then
      GPSTick = "*"      ' used in any form to show service is actively polling for GPS based on a changing location (is service running?)
    End If                ' use a timer in other modules to retrieve this data ( GPS_LocationChanged works in other modules (sometimes) but I don't know how????)
 
    If count Mod 5 = 0 Then
      GPSTick = ""      ' Make GPStick flash on any form that uses it.
    End If
   
    If count Mod 10 = 0 Then  ' determine if it is time to switch files AND flush buffered data to disk (Writer does buffer data - so commit it often - or lose it)
      fWriter.Flush
      'CodeMod.Odom = Distance
      'CodeMod.SaveDef
     
      If File.Size(MyDir,fGPSFileName) > GPSFileSize Then
          If GPSStarted = False Then  ' show when service has not inited (possibly redundant since service must be running to get here)
            ToastMessageShow("GPSRecords File Size: "&File.Size(MyDir,fGPSFileName), False)
          End If
          fWriter.Close      ' instead of using a circular file buffer (hard to control) use two files to save GPS data
          SetGPSFileName      ' when the file in use gets to max file size, delete the other file and start using it....
      End If                ' the goal is to have the last x (hour) saved for reconstruction in case needed (ie. accident)

    End If   
    If count Mod 50 = 0 Then        ' more debug stuff....
      If GPSStarted = False Then
          ToastMessageShow(fGPSFileName&"  - Current File Size:  "&File.Size(File.DirRootExternal,fGPSFileName), True)
      End If     
    End If

   
End Sub


Sub SetGPSFileName  ' determine which file to use when recording new data - not perfect but gets us by

  If fGPSFileName = "GPSRecords.txt" Then
      fGPSFileName = "GPSRecords1.txt"
  Else
      fGPSFileName = "GPSRecords.txt"
  End If
 
  If File.Exists(MyDir,fGPSFileName) Then
      File.Copy(MyDir,fGPSFileName,MyDir,fGPSFileName&".BAK")
      File.Delete(MyDir,fGPSFileName)
  End If
 
  '  **************  NOTE  ******************
  '  "DirRootExternal" - "This is currently NOT my SD external card - WTF?"
  '  Any file explorer I use shows 2 dirs - "external_sd"  and "sdcard"
  '  Using "DirRootExternal" stores data to internal RAM (sdcard)- NOT the external sd card (as I expected) WTF?
  '  Android is Truely wonderful - when you understand it....
 
  fWriter.Initialize(File.OpenOutput(MyDir,fGPSFileName,True)) ' we closed the file handle earlier - restart (init) it...   
 
  If GPSStarted = False Then    ' if not already running - this message will toast.. (more visual debug)
      ToastMessageShow("Deleted Old File and Record to New GPSRecords File Name:  "&fGPSFileName, True)
  End If

End Sub


Sub InitGPSFileName
  Dim a, b As Long

  a = File.LastModified(MyDir,"GPSRecords.txt")
  b = File.LastModified(MyDir,"GPSRecords1.txt")

  If a > b Then                        ' which file was written to last?  Use the "other" file when we start up (if older). 
    fGPSFileName = "GPSRecords1.txt" 
  Else
    fGPSFileName = "GPSRecords.txt"  ' set the filename we shall use to record data to...
  End If
 
  fWriter.Initialize(File.OpenOutput(MyDir,fGPSFileName,True))   
 
  If GPSStarted = False Then          ' Don't show toasts unless this service has stopped
    ToastMessageShow("GPSRecords File Name:  "&fGPSFileName, True)  '  show message if GPS record system has not started
  End If
End Sub


Sub RecordGPSFile
  fWriter.WriteLine(fGPSstr)          '  record data to a file - set by function "InitGPSFileName"

End Sub


Sub GPS_GpsStatus (Satellites As List)  ' get valid and number of sats in view.
Dim SatCount As Int
    SatCount = 0
    For i = 0 To Satellites.Size - 1
        Dim Satellite As GPSSatellite
        Satellite = Satellites.Get(i)
        If Satellite.UsedInFix = True Then SatCount = SatCount + 1
    Next
    fSats  = SatCount &" out of "&Satellites.Size&" in view"  ' the entire string of valid sats and the total number of sats
    fvSats = SatCount                                        ' just valid sats int
End Sub


Sub GetDistance(lat1 As Double, long1 As Double, lat2 As Double, long2 As Double) As Double
    Dim rlat1, rlong1, rlat2, rlong2, p1, p2, p3, ret As Double
   
    rlat1 = DEGREES_TO_RADIANS * lat1
    rlong1 = DEGREES_TO_RADIANS * long1
    rlat2 = DEGREES_TO_RADIANS * lat2
    rlong2 = DEGREES_TO_RADIANS * long2
   
    p1 = Cos(rlat1) * Cos(rlong1) * Cos(rlat2) * Cos(rlong2)  ' funcky code to measure distance - works very well so far
    p2 = Cos(rlat1) * Sin(rlong1) * Cos(rlat2) * Sin(rlong2)  ' dont ask me how it works - but it does!!!
    p3 = Sin(rlat1) * Sin(rlat2)
   
    ret = p1 + p2 + p3
   
    If ret >= 1 Then ' greater than or equal to - otherwise NAN (not a number ) error
        Return 0
    Else
        ret = ACos(ret)
        ret = (ret * EARTH_RADIUS)
        'ToastMessageShow(" PVals: "&p1&"  -  "&p2&"  -  "&p3&CRLF&" Ret1: "&ret1&"  Ret2: "&ret2&"  Retp: "&retp&"  Res: "&ret  ,True)
        Return ret
    End If
End Sub


Sub Service_Destroy

    ToastMessageShow(" GPS Service Has Stopped Running", True)
    GPSStarted = False
    StartServiceAt( "", DateTime.Now + 3000000000000 * 1000, False) ' Stop service - set way into the future
   
    fWriter.Close    ' stop writing if service gets destroyed - close the file properly
   
End Sub
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
I would suggest you also attach your project, it is a large code.

The whole project is MUCH larger... (I can't find the attach file option either??? or I would have attached this bal as file).
This is just meant to demonstrate a GPS service module - and things you can do with it. Simple GPS service modules exist here; that's where I started from.

Thanks
 
Upvote 0

NJDude

Expert
Licensed User
Longtime User
You could upload the ZIP to Dropbox or any other file sharing service. (Open the B4A IDE and then click on FILE -> Export To ZIP)

If the code is very large then just create a sample with the relevant code.
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Sorry, app is private. Creating a sample would be akin to creating the whole project (again).
Hopefully, enough comments exist to form some logic of what is going on (however rambling).
The GetDistance function is very useful for accumulating distance traveled using GPS alone. Measured with my own vehicle odometer, it is surprisingly very accurate. Even in BC, up and down mountains, it maintains accuracy to 1/10th of a kilometer.

Please accept my apologies and thank you for your much valued input.
 
Upvote 0
Top