Android Question ServiceStartAt - possible solution for TargetSDKVersion 19 and above

wes58

Active Member
Licensed User
I have been using ServiceStartAt to start the service and found out that the difference in scheduled and actual start times can be several minutes. See the log below:
06:03:06 - Next Start at 19/05/15 21:30:00
Ticks - 1432036800000

21:34:02 *** Service start ***
Intent (Intent) Intent { flg=0x4 cmp=com.NotifyMe/.notificationservice (has extras) }
Extras Bundle[{android.intent.extra.ALARM_TARGET_TIME=1432036800000, android.intent.extra.ALARM_COUNT=1}]
21:34:04 - Next Start at 20/05/15 06:00:00
Ticks - 1432067400000

06:07:08 *** Service start ***
Intent (Intent) Intent { flg=0x4 cmp=com.NotifyMe/.notificationservice (has extras) }
Extras Bundle[{android.intent.extra.ALARM_TARGET_TIME=1432067400000, android.intent.extra.ALARM_COUNT=1}]
Data null
06:07:12 - Next Start at 20/05/15 21:30:00
Ticks - 1432123200000
After reading about AlarmManager, I have found out that the problem can be with the applications that have TargetSDKVersion 19 or above and use the AlarmManager set function.
public void set (int type, long triggerAtMillis, PendingIntent operation)
Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.

Applications whose targetSdkVersion is before API 19 will continue to get the previous alarm behavior: all of their scheduled alarms will be treated as exact.
The recommended method to use is setExact
public void setExact (int type, long triggerAtMillis, PendingIntent operation)
Schedule an alarm to be delivered precisely at the stated time.

This method is like set(int, long, PendingIntent), but does not permit the OS to adjust the delivery time. The alarm will be delivered as nearly as possible to the requested trigger time.

Note: only alarms for which there is a strong demand for exact-time delivery (such as an alarm clock ringing at the requested time) should be scheduled as exact. Applications are strongly discouraged from using exact alarms unnecessarily as they reduce the OS's ability to minimize battery use.
I did it using inline Java but the question for Erel is, that maybe he could implement it in the B4A Core.jar for StartServiceAt function?
 

wes58

Active Member
Licensed User
And here is a sample code that can be used to start the service
B4X:
'Declare in Globals    
        Dim srvAtExact As JavaObject

'for example, in your sub where you want to start service 
Sub ServiceSchedule(h as Int, m as Int)
    Dim NextStartTime As Long    'time in ticks for next start

        NextStartTime = DateTime.TimeParse(DateTime.Time(DateTime.Now)) + h * DateTime.TicksPerHour + m * DateTime.TicksPerMinute
        srvAtExact.InitializeContext
        srvAtExact.RunMethod("StartServiceAtExact", Array(NextStartTime, True))
'        srvAtExact.RunMethod("StartServiceAtExact", Array(Me, NextStartTime, True))      
End Sub

#If JAVA
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
    public void StartServiceAtExact(Long time, Boolean wakeUp){
        AlarmManager alMan = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this.getApplicationContext(), this.getClass());
        PendingIntent    penInt = PendingIntent.getService(this.getApplicationContext(), 1, intent, 134217728);
        alMan.setExact(wakeUp?AlarmManager.RTC_WAKEUP:AlarmManager.RTC, time, penInt);
    }
/*
    public void StartServiceAtExact(Class service, Long time, Boolean wakeUp){
        AlarmManager alMan = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this.getApplicationContext(), service);
        PendingIntent    penInt = PendingIntent.getService(this.getApplicationContext(), 1, intent, 134217728);
        alMan.setExact(wakeUp?AlarmManager.RTC_WAKEUP:AlarmManager.RTC, time, penInt);
    }
*/

#End If
Maybe someone will find it useful.
 
Top