Android Question Best way to call a service every 30 minutes

Anser

Well-Known Member
Licensed User
Longtime User
Hi all,

I need a push in the right direction.

I already have a Service named 'DeviceLocation' that when called will pick the devices location and write the details to a remote server.

Now I would like to run this service named 'DeviceLocation' ie fetching the location details and updating the remote server every 30 minutes.

What is the best way to move forward. I searched the forums, but I find lot of scattered information, some are outdated and not relevant as of now for eg. Sticky service which is outdated, some discussions about PhoneWake partial lock or else the the service will not be called if the device is sleeping etc etc

Can I use a timer in Starter Service to call a service named 'DeviceLocation' every 30 minutes. ? Is it guaranteed that if the DATA and LOCATION in the device is ON, then it will will send the device's location to the remote server for sure ? Do I need to use PhoneWake partial lock ? If yes at which point ? Should I use PhoneWake partial lock inside the service 'DeviceLocation' ?

Any simple sample that shows how to call a service every 30 minutes and also the trick that ensure that the service 'DeviceLocation' will be called even when the device is sleeping. I believe that this may be useful for many others in this forum. I expect the app to run perfectly from Android ver 4.1 onward to the latest

I need an advice.

Thanks in advance
 

Powie

Member
Licensed User
Longtime User
I do the same in my project.

I have defined the interval in a code module named madb:

B4X:
Dim FinderRescanMinutes As Int = 30

In the service, after the run of the gps,etc...

->

B4X:
StartServiceAt("", DateTime.Now + ( madb.FinderRescanMinutes * DateTime.TicksPerMinute) , False)
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
B4X:
StartServiceAt("", DateTime.Now + ( madb.FinderRescanMinutes * DateTime.TicksPerMinute) , False)
Thank you. Unfortunately, I am still confused.

I would like to know where exactly is the above line ie StartServiceAt() is to be used.
Is it inside the Starter Service's Service_Create or inside the Service_Create of the Service named 'DeviceLocation' (as per my question) ?

So with this StartServiceAt(), I don't have to use any timer ?
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Sorry, you have already written it
In the service, after the run of the gps,etc...
B4X:
StartServiceAt("", DateTime.Now + ( madb.FinderRescanMinutes * DateTime.TicksPerMinute) , False)

So no timer required ? No PhoneWake partial lock required ?
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
For me it is still confusing. In the end of your Service_Start() you are calling Service.StopAutomaticForeground
May be I need a break.
Would be nice if someone can provide a list with the steps/the rules to be followed to call a service every 30 minutes that works even if the device is in sleep mode or battery saving mode
 
Upvote 0

Powie

Member
Licensed User
Longtime User
If you like to have it simple, after service start, call ServiceStart at and calculate the time + 30 minutes......
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
The below given code is working fine for the past 2:30 hrs. I mean this service is running every 5 minutes for the past 2:30 hrs now. Now the ONLY problem that I see is that I see a non dismiss able Notification on the phone. This was not there before I used StartServiceAt. Is there any way to avoid this Notification ?

'DeviceLocation' Service
B4X:
#Region  Service Attributes
    #StartAtBoot: False
 
#End Region

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

    Private FusedLocationProvider1 As FusedLocationProvider
    Private LastLocation As Location
    Private Pw As PhoneWakeState

End Sub

Sub Service_Create
   FusedLocationProvider1.Initialize("FusedLocationProvider1")
 
   Service.StopAutomaticForeground
End Sub

Sub Service_Start (StartingIntent As Intent)
    Log("Inside Service start")
    Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED
 
   'I am not sure whether PartialLock is required if we use StartServiceAt
    Pw.PartialLock

    If FusedLocationProvider1.IsInitialized = False Then
        FusedLocationProvider1.Initialize("FusedLocationProvider1")
    End If
 
    If FusedLocationProvider1.IsConnected = False Then
        FusedLocationProvider1.Connect
    End If
 
   ' Starter.nLocTrackInterval = 5  which means 5 minutes
    Log("LocTrackInterval = " & Starter.nLocTrackInterval)
    If Starter.nLocTrackInterval > 0 Then
        StartServiceAt(Me, DateTime.Now + ( Starter.nLocTrackInterval * DateTime.TicksPerMinute) , False)
    End If
 
End Sub

  • I am not clear whether I should use #StartAtBoot: False or #StartAtBoot: True ? ( As of now, #StartAtBoot: is False and In the Starter Service Service_Start I have called this service via CallSubDelayed. May be with #StartAtBoot: True I can avoid that. Not sure.)
  • I am not sure whether PartialLock is required if we use StartServiceAt ?
  • Should I call Service.StopAutomaticForeground in the Service_Destroy() ?
  • While running the app, why do I see a non dismiss able Notification on the phone. ? Is it because that I am using StartServiceAt ? OR is it because of the Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED entry in the Service_Start() ?. Is this really required ?
Require a confirmation from the Experts regarding the above concerns.

If I get answers for the above, may be I can write a well disciplined code, the way it is supposed to be used.

Still so much to learn :)
 
Last edited:
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Applied #StartAtBoot: True and is working fine.
Eliminated PartialLock. Stil it is working as expected, so I assume that if we use StartServiceAt(), acquiring a partial lock may not be required

I scheduled the service to run every 60 minutes. So far working fine every one hour for the past 9 hrs

After the app runs for few hours, I see a non dismiss able Notification on the phone with the App's name. As of now, do not know why it is appearing and do not know how to eliminate this
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
I can't get this working continuously. It works for 2 to 3 hrs after that it dies. I am testing this on Android 8.0.0 on Samsung Note 8

Any help will be appreciated.
Here is the outline of the code used in DeviceLocation service
B4X:
#Region  Service Attributes
    #StartAtBoot: True
#End Region

Sub Process_Globals
    Private FusedLocationProvider1 As FusedLocationProvider
    Private LastLocation As Location   
    Private Pw As PhoneWakeState

End Sub

Sub Service_Create
    FusedLocationProvider1.Initialize("FusedLocationProvider1")
        
    Service.StopAutomaticForeground   
End Sub

Sub Service_Start (StartingIntent As Intent)
    Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED
    
    Pw.PartialLock
    
    If FusedLocationProvider1.IsInitialized = False Then
        FusedLocationProvider1.Initialize("FusedLocationProvider1")
    End If
    
    If FusedLocationProvider1.IsConnected = False Then
        FusedLocationProvider1.Connect
    End If
    ' Starter.nLocTrackInterval value is 5, (for testing purpose)
    If Starter.nLocTrackInterval > 0 Then
        StartServiceAt(Me, DateTime.Now + ( Starter.nLocTrackInterval * DateTime.TicksPerMinute) , False)
    End If
    
End Sub

Sub Service_Destroy
    
    If FusedLocationProvider1.IsConnected = True Then
        FusedLocationProvider1.Disconnect
    End If

End Sub

Sub FusedLocationProvider1_ConnectionSuccess

    Dim LocationRequest1 As LocationRequest
    LocationRequest1.Initialize
    LocationRequest1.SetInterval(1000)    '    1000 milliseconds
    LocationRequest1.SetFastestInterval(1000) 'Added by anser on 20-Jul-2018
    LocationRequest1.SetPriority(LocationRequest1.Priority.PRIORITY_HIGH_ACCURACY)
    LocationRequest1.SetSmallestDisplacement(1)    '    1 meter
    
    Dim LocationSettingsRequestBuilder1 As LocationSettingsRequestBuilder
    LocationSettingsRequestBuilder1.Initialize
    LocationSettingsRequestBuilder1.AddLocationRequest(LocationRequest1)
    FusedLocationProvider1.CheckLocationSettings(LocationSettingsRequestBuilder1.Build)
    
    FusedLocationProvider1.RequestLocationUpdates(LocationRequest1)
End Sub

Sub FusedLocationProvider1_LocationChanged(Location1 As Location)
    Log("FusedLocationProvider1_LocationChanged")
    FileWrite(DateTime.Now & " - FusedLocationProvider1_LocationChanged")
    LastLocation=Location1

    UpdateDb 'Write to Table
End Sub

Sub UpdateDb
    'My Routine to update the database
    ....
    ....
    Pw.ReleasePartialLock
End Sub
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
Noted the mistakes. Is there anything else that I should take care for eg inside the Service_Destroy() ?
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
I am testing this on Samsung Galaxy Note 8 running Android version 8.0.0

These are my observations.

In the service_create I have used Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_ALWAYS
B4X:
Sub Service_Create

    Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_ALWAYS
End Sub

Method 1: Remove the code Service.StopAutomaticForeground from the Service_Start

This test is running fine for more than 2 hrs and the service is running every 15 minutes, so far good. This method is working fine, but always displays a non-dismiss-able notification with the app's name on the device.

I don't prefer to have this notification displayed ALWAYS on the device. Would like to know that is there a way to get this working without having non-dismiss-able notification always ?

Method 2: Include the code Service.StopAutomaticForeground in the Service_Start

Applying this method, it works up to 45 minutes, after that the service stops. I assume that the OS kills this eventually. Good thing is that the non-dismiss-able notification is NOT there on the device.

If I keep the code Service.StopAutomaticForeground in the Service_Start, the Service works for 3 times (scheduled to run every 15 minutes), after that even though the StartServiceAt(Me, nAfter15Minutes, False ) is called/scheduled, the service dies itself and is never executed.

As per the notes, it is advised to keep the 3rd parameter as False in StartServiceAt() or else there may be heavy battery drainage, so I have used False.

So my question is that
  • Whether a scheduled service can work WITHOUT always displaying a non-dismiss-able notification on the device ?
  • Is Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED is the solution to avoid the ALWAYS non-dismiss-able notification on the device ? In that case what will happen if the OS kills the app ? Will the scheduled service work ?
  • Will this works the same way on all Android version below 8.0.0
  • As of now, I have used Pw.PartialLock in Service_Start is this really required ?

Any help will be appreciated.

Update : Tried using Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED instead of Service.AUTOMATIC_FOREGROUND_ALWAYS. The result is that the schedule will not work after 45 minutes. So this is not a solution
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Is Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_WHEN_NEEDED is the solution to avoid the ALWAYS non-dismiss-able notification on the device ?
Yes. You need to use StartServiceAt to schedule the next run each time. Do whatever you need to do and call StopAutomaticForeground.
 
Upvote 0
Top