0

I am writing an Android app to alert the user an event in "almost" real time. The app sends an HTTP Get request asynchronously, and processes the received result when it arrives to determine the state of the event. To be reasonably up-to-date, the HTTP requests need to be made every 15-60 seconds.

I have implemented this using a foreground service, thinking this would allow the alert when the app is in the background. The service contains the following code to handle the recurring requests (with an AsyncTask subclass to handle the actual HTTP request):

    Handler queryHandler = new Handler();
    runQuery = new Runnable() {
        @Override
        public void run() {
            new HTTPGetTask().execute(urlString);
            queryHandler.postDelayed(runQuery, queryFrequencyInMilliseconds);
        }
    };

It works fine until the device sleeps. Then the service sleeps as well, only waking and reporting status at intervals that are far too long to be useful.

I've been reading about AlarmManagers, Partial WakeLocks, WakefulBroadcastReceivers, and Job Schedulers. (e.g., Keep a Service running even when phone is asleep). I need to target older devices (API level 19) so the JobScheduler approach is out.

There are clearly a number of approaches to scheduling recurrent tasks, but it seems that the best approach depends a number of factors, including length of task, frequency of task, how precise the timing needs to be. For example, Android documentation on AlarmManager states

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

Any suggestions on best approach / design pattern for an HTTP request repeating every 15 - 60 seconds, given that the returned result is small, and that the user needs to get the result in a timely fashion when the app is in the background and even if the device sleeps? The timing doesn't need to be exact, but should be reasonably consistent.

(edited to add) Typical use case is that the service would be in operation for 5 to 30 minutes, and would stop once a final event state had been received and the user alerted. I would also probably have a maximum allowed running time of 30 - 60 minutes.

Community
  • 1
  • 1
bphi
  • 1,015
  • 6
  • 16
  • 1
    Should you be using push notifications for this? I.E., have the Server tell the device when something needs to happen and not for the device to poll? Do you have any control on the server side to do this? – Gavin Harris Feb 16 '17 at 04:19
  • Push notifications not an option here, unfortunately. (No control over server, no option to request them) – bphi Feb 16 '17 at 04:46
  • 1
    Could you 'cheat' in this case? Can you put a simple server between your source server and device? If you are making a network ping every 15 - 60 seconds you will drain the battery in no time (you need to keep the radio alive which is not a good thing!). If you could use a small node server to do the logic on your devices behalf then you can ping the device when there is something interesting to see? – Gavin Harris Feb 16 '17 at 05:27
  • Short term (while I'm the only use of the app, and very cognizant of power use) I've implemented a simple partial wake lock. However, doing this server-side really makes more sense; I hadn't considered an intermediary server, but that could completely eliminate the need for polling as you indicated, and would actually provide some ancillary benefits as well. If you provide this as an answer I'll accept it. – bphi Feb 20 '17 at 00:57

1 Answers1

1

If you have the ability to implement an intermediary server, you could use that to Poll the source server and then provide Push Notifications to the individual devices as needed.

This will mean that your Devices will only need to 'talk' to the network when it is needed (saving Battery etc).

If you are up on AWS, you can use a CloudWatch Timed Event which invokes a Lambda function to call your 'base' server. If there is anything that needs communicating to the devices you can then invoke the Push Notif service (again AWS has SNS or you can just call GCM (Firebase Messaging) or APNS directly).

Good luck! Gav

Gavin Harris
  • 652
  • 5
  • 15