Android Question Scheduled Events

Declan

Well-Known Member
Licensed User
Longtime User
Reading this topic about Calculating the next scheduled time:
How can I incorporate this into a Service where I can use CallSubDelayed to trigger an event in Activity Main when one of the three times are met?
The code from above link:
B4X:
Dim t As Long = FindNextTime(Array As Double(5, 6.5, 20))
Log($"Next time is: $DateTime{t}"$)

Sub FindNextTime(Times As List) As Long
   Times.Sort(True)
   For Each st As Double In Times
     If SetHours(st) > DateTime.Now Then
       Return SetHours(st)
     End If
   Next
   Return DateTime.Add(SetHours(Times.Get(0)), 0, 0, 1)
End Sub

Sub SetHours(st As Double) As Long
   Dim hours As Int = Floor(st)
   Dim minutes As Int = 60 * (st - hours)
   Return DateUtils.SetDateAndTime(DateTime.GetYear(DateTime.Now), _
       DateTime.GetMonth(DateTime.Now), DateTime.GetDayOfMonth(DateTime.Now), hours, minutes, 0)
End Sub


 

Declan

Well-Known Member
Licensed User
Longtime User
From my Service "Starter" I wish to start the Service "Schedule" three times a day, every day: 7am, 2pm and 7pm.
The Service "Schedule" will then call a Sub in my Activity "Main".
Seems simple - But driving me crazy
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
From my Service "Starter"
Thanks. Let's think about the problem :
  • you can of course Schedule the first launch of the Schedule service from Starter and Schedule will start without any problem
  • when the Schedule service had been started, Starter can't be used again to restart Schedule because it is already running. So the solution is to schedule again the service named Schedule from itself at 7am, 2pm and 7pm (using StartServiceAtExact)

But the problems I can see about the first schedule is this one : as you probably know, Starter (if paused) will be started (if it is paused) when the service Schedule will start the next execution time (should not happen but why not). In that last situation, Starter will erase any already scheduled time by the service Schedule.

So, in my opinion, the Starter service should not be used to manage the scheduling of the service Schedule. In that situation, the Schedule service should be started by the Activity for its first launch, put in StartAtBoot mode and include all the logic to schedule its execution.
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
Cool, I have now got:
Starter Service:
B4X:
#Region  Service Attributes
    #StartAtBoot: True
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals

End Sub

Sub Service_Create

End Sub

Sub Service_Start (StartingIntent As Intent)
    StartService(Schedule)
End Sub

Schedule Service:
B4X:
#Region  Service Attributes
    #StartAtBoot: true
  
#End Region

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

End Sub

Sub Service_Start (StartingIntent As Intent)
    Dim t As Long = FindNextTime(Array As Double(13.5,13.55, 13.6))
    Log($"Next time is: $Time{t}"$)  
  
    StartServiceAt(Me,t,True)
   


End Sub
Sub FindNextTime(Times As List) As Long
   Times.Sort(True)
   For Each st As Double In Times
     If SetHours(st) > DateTime.Now Then
       Return SetHours(st)
       Log("This is SetHours: " & SetHours(st))
     End If
   Next
   Return DateTime.Add(SetHours(Times.Get(0)), 0, 0, 1)
End Sub

Sub SetHours(st As Double) As Long
   Dim hours As Int = Floor(st)
   Dim minutes As Int = 60 * (st - hours)
   Return DateUtils.SetDateAndTime(DateTime.GetYear(DateTime.Now), _
       DateTime.GetMonth(DateTime.Now), DateTime.GetDayOfMonth(DateTime.Now), hours, minutes, 0)
End Sub

Sub Service_TaskRemoved
    'This event will be raised when the user removes the app from the recent apps list.
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy

End Sub

Log:
B4X:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Service (schedule) Create **
** Service (schedule) Start **
Next time is: 13:30:00
** Service (schedule) Start **
Next time is: 13:33:00
** Service (schedule) Start **
Next time is: 13:35:00
** Service (schedule) Start **
Next time is: 13:30:00

Each time "Schedule" starts, it calls the same activity in Main.
Just just do that now
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Starter Service:
B4X:
#Region  Service Attributes
    #StartAtBoot: True
Dont use startatboot at the starterservice. Use another service and set startatboot here
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
I now have the Schedule running.
But have a problem with calling the sub if times are correct:
B4X:
Sub Service_Start (StartingIntent As Intent)
    Dim t As Long = FindNextTime(Array As Double(16.15,16.2, 16.25))
    Log($"Next time is: $DateTime{t}"$)  
  
    StartServiceAt(Me,t,True)
   
    If Abs(DateTime.Now - t) < 30 * DateTime.TicksPerSecond Then
        LogColor("Gotcha",Colors.Red)
        Log($"Now: $DateTime{DateTime.now}"$)
        CallSub(Main, "ImgDisplay")
    Else
        LogColor("Gotcha",Colors.Blue)
        Log($"Now: $DateTime{DateTime.now}"$)
    End If
End Sub
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
You can check if the activity is running. If yes, use callsubdelayed. If not, use startactivity
Thanks Manfred - The activity is always running so I have no problem there.
The problem I have is with this:
B4X:
    If Abs(DateTime.Now - t) < 30 * DateTime.TicksPerSecond Then
        LogColor("Gotcha",Colors.Red)
        Log($"Now: $DateTime{DateTime.now}"$)
        CallSub(Main, "ImgDisplay")
    Else
        LogColor("Gotcha",Colors.Blue)
        Log($"Now: $DateTime{DateTime.now}"$)
    End If
Log:
B4X:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **~i:** Activity (main) Resume **
** Service (schedule) Create **
** Service (schedule) Start **
Next time is: 09/23/2016 16:15:00
Gotcha
Now: 09/23/2016 16:10:59
** Service (schedule) Start **
Next time is: 09/23/2016 16:16:00
Gotcha
Now: 09/23/2016 16:15:00
** Service (schedule) Start **
Next time is: 09/24/2016 16:15:00
Gotcha
Now: 09/23/2016 16:16:00

For some reason this aint working:
B4X:
If Abs(DateTime.Now - t) < 30 * DateTime.TicksPerSecond Then
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
you want to substract a date in the future from the current date? Compare DateTime.Now and t and you´ll see this is not what you are searching. Aehem; that´s my guess.

I don´t know what exactly you want to check here.

The shedule is started.
It just have to do the things what you need and then it should reshedule itself for the next run and then it should finish itself. Finish.

Maybe i just do not understand what you want to archieve here. I guess it will always "match"
Imagine the Now has a value of 3000 (just for this example). t (which is a date in the future) must have an higher value. Let´s say 4000.
B4X:
If Abs(DateTime.Now - t)
->
If Abs(3000  - 4000)
3000-4000=-1000

so. -1000 will always be smaller than 30 * DateTime.TicksPerSecond. Or not?
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
@manfred.
Many thanks, that is exactly what I was trying to achieve.
More importantly - I now fully understand how it works.
Maybe you should post this as a Tutorial.
 
Upvote 0
Top