Android Question Run a service every hour while phone sleeps

gezueb

Active Member
Licensed User
Longtime User
I use a service to get the sea level air pressure (QNH) from the internet every hour and store it into a ring buffer. I used an example from the forum to repetitively schedule this cyclic process with phone wake state in partial lock. I removed the call to StartServiceat as Erel said it would not work on recent Android versions anymore. The App works alright, but sucks the battery.
Is there still another method to start a service repetively that does not require a partial lock? I am confused because the forum provides methods and examples that seem not work anymore thanks to Googles "progress" :oops:.
 

gezueb

Active Member
Licensed User
Longtime User
I have investigated these links in post #2. While they have certainly once been valid and useful, Google now prohibits to start services when the app is in the background (see Android Tutorial "Bachkground location tracking" post #14 by Erel). Obviously it must still be possible, otherwise many apps e.g. messengers would not work, but not available for the lowly programmer. The problem that many advices in the forum are not usable anymore on newer smartphones with SDK 30+ is not the fault of Erel or his team, but it gets increasingly more difficult to find solutions that still work on phones old and young:mad: (e.g. access to files from other apps etc).
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
you need to look into receivers. a lot of time has been
spent (mostly by @Erel) explaining how to deal with
android's changes and how to migrate services to
receivers.
 
Upvote 0

gezueb

Active Member
Licensed User
Longtime User
ok, I will try to understand this and thanks for the tip. However, I was always a fan of b4a because it was easy to program without knowing to much about the intricacies of Android. Sadly, i have grown too old to understand why things do not work anymore that have been working so far. My app works perfectly allright on one of my older phones but not on my recent Galaxy Flip. No error messages, no logs, the b.... service just stops working!
I do now include the service in the hope that someone can tell me how that could work. The service is started from the main activity, not from boot up.

B4X:
'    This service module provides a background task that updates QNH value onto a file
'     the service is started from the Main, not at boot

#Region  Service Attributes
    #StartAtBoot: false
#End Region
'    this service module works in the background (phone sleeping) and cyclicly update barometric pressure and saves it into a file
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Private nid As Int = 1 ' Notification ID.
    Private lock As PhoneWakeState
    Private tmrForClock As Timer

   
End Sub

Sub Globals
   
End Sub

Sub Service_Create
    Log("--------------------------")
    Log("At Service_Create")
    Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER 'we are handling it ourselves
    lock.PartialLock
End Sub

Sub Service_Start (StartingIntent As Intent)

    Log("--------------------------")
    Log("At Pages service module Service_Start at: " & _
        DateTime.GetHour(DateTime.Now) & ":" & DateTime.GetMinute(DateTime.Now) & ":" & DateTime.GetSecond(DateTime.Now))
'    the following code sends a notification displayed as "Benachrichtigung"
    Service.StartForeground(nid, CreateNotification("Tapping this notification will open the app."))
'    StartServiceAt(Me, DateTime.Now + 30 * DateTime.TicksPerMinute, True) 'this is no longer required and not allowed in modern sdk
    InitializeAndStartWhatsNeeded
End Sub

Sub Service_Destroy
    lock.ReleasePartialLock
End Sub

' Handlers.
'----------
Sub tmrForClock_Tick
   
    Log("Ticking at: " & _
        DateTime.GetHour(DateTime.Now) & ":" & DateTime.GetMinute(DateTime.Now) _
        & ":" & DateTime.GetSecond(DateTime.Now))
'        'now read the QNH from the internet
    Dim job As HttpJob
    Dim Link As String
    Dim httpstring As String
    'get QNH once when activity is created
    Link = "https://www.checkwx.com/weather/"&Main.Station&"/metar"
    job.Initialize("",Me)
    job.Download(Link)
'    Log ("Looking for Link")
    Wait For (job) JobDone(job As HttpJob)
    If Not(job.Success) Then    'this test is only used to show if the internet fails
        Dim message As String
        message = job.ErrorMessage
        Log("httpjob failed"&message)
    Else
        httpstring = job.GetString
        Dim Result As String 'does not work if a string manipulated on itself
        Dim startindex As Int
        Dim localQNH As Int
        Result = httpstring 'copy passed string to local variable
        '    Log ("httpstring length: "&Result.Length)
        job.Release 'we no longer need the resources
        startindex = Result.IndexOf("Pressure") 'look for keyword pressure
        If startindex = -1 Then
            Log("Pressure not found")
        Else
'        Log("Pressure found at index:"&startindex)
            startindex = Result.IndexOf2(">",startindex) 'skip twice a >
'        Log(startindex)
            startindex = Result.IndexOf2(">",startindex+1)
'        Log(startindex)
            localQNH = Result.Substring2(startindex+1,startindex+8)
            Log("QNH in "&Main.Station&": "&localQNH)
            Main.QNH =  localQNH
            AddtoBuffer(localQNH)
            StartServiceAt(Me, DateTime.Now + 58 * DateTime.TicksPerMinute, True) 'this is no longer required and not allowed in modern sdk ?!
        End If 'parsing successful acquisition
    End If
End Sub

' Misc. sub routines.
'--------------------
Sub CreateNotification (Body As String) As Notification 'shows a notification on the phone start page
    Dim notification As Notification
    notification.Initialize2(notification.IMPORTANCE_LOW)
    notification.Icon = "icon"
    notification.SetInfo("Now running in the background.", Body, Main)
    Return notification
End Sub

Sub InitializeAndStartWhatsNeeded

      tmrForClock.Initialize("tmrForClock", DateTime.TicksPerHour)  
'    tmrForClock.Initialize("tmrForClock", DateTime.TicksPerMinute) 'for tests only
    tmrForClock.Enabled = True
    tmrForClock_Tick 'force one QNH query before the cycles begin. So we have a QNH to start in the main.
End Sub

'add to buffer with timestamp is more complex as without since b4x is not able to
'handle read and write list with custom types. So we squeeze QNH, day and hour into
'a single string.

Sub AddtoBuffer(QNHitem As Float)
    Dim QNHString As String = NumberFormat2(QNHitem,4,0,0,False)
    Dim Day As String   = NumberFormat2(DateTime.GetDayOfMonth(DateTime.Now),2,0,0,False) 'easier to parse that way
    Dim Hour As String  = NumberFormat2(DateTime.GetHour(DateTime.Now),2,0,0,False)
    Main.QNHList.Add(QNHString&","&Day&","&Hour)
'    Main.QNHList.InsertAt(0,QNHitem) 'inserts the new value leftmost
    If Main.QNHList.Size > 100 Then
        Main.QNHList.RemoveAt(0) 'deletes the leftmost
    End If
    'now write it to a text file, no append
    File.WriteList(File.DirInternal,"QNHbuffer.txt",Main.QNHList) 'the whole buffer is written to the file
    Log ("get Text: "&File.GetText(File.DirInternal,"QNHbuffer.txt"))
    Main.UpdateFlag = True
End Sub
 
Last edited:
Upvote 0

toby

Well-Known Member
Licensed User
Longtime User
Sadly, i have grown too old to understand why things do not work anymore that have been working so far.
Thanks to Google for changing Android. Therefore blame Google for all the troubles you're facing .
 
Upvote 0

gezueb

Active Member
Licensed User
Longtime User
I could not agree more. Erel, his team and all the experts do a marvellous job to navigate us through the troubles caused by Google who took possession of an erstwhile open source OS and displays a "dont care" attitude against backwards compatibility. I know that Android must evolve like any other system, and it's okay if it ask now permissions for this and that, but its a bit thick that important os features are now hidden and just available for the nice guys that bring money through ads.
 
Upvote 0

gezueb

Active Member
Licensed User
Longtime User
According to the above mentionned tutorial "Background location tracking" post #14 by Erel this does not work anymore. But thank you anyway :)
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
I use it and it does, tested on all versions on android. I do use a partial lock, and have managed to overcome the battery suck. You need to experiment with this. All our apps are commercial apps and used by 10's of thousand of users.
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
I could not agree more. Erel, his team and all the experts do a marvellous job to navigate us through the troubles caused by Google who took possession of an erstwhile open source OS and displays a "dont care" attitude against backwards compatibility. I know that Android must evolve like any other system, and it's okay if it ask now permissions for this and that, but its a bit thick that important os features are now hidden and just available for the nice guys that bring money through ads.
this may look like a rant better placed in the chit-chat area, but maybe we should stop thinking of phones being like our old pre-network era personal computers.
these devices are more like wallets that keep most of our personal data (location, behavior, money...) so protection of this data from intentional or erroneous actions must be ensured.
i see the ever-increasing OS-enforce limits as steps in this direction.
and yes, it's a pain to update our apps at every OS iteration...
 
Upvote 0

gezueb

Active Member
Licensed User
Longtime User
My app now works with a servicemodule acquiring partial lock and using a one hour timer. I am a bit confused about the advice to use StartServiceAt.
Should I discard the timer and re-schedule the service app after it has done its stuff? What does the service app in between? Should I destroy it?
 
Upvote 0

gezueb

Active Member
Licensed User
Longtime User
This link provides info that I was missing:

Now I know that a service running in the background should work in the foreground state:oops: It's quite simple really!
This is a new version of Schroedingers Cat. She can run in foreground mode and be in the background at the same time.
But when you open the box, there is a large probability that the pour ? is dead, killed by a new Android flavor?
 
Last edited:
Upvote 0
Top