Requirement - I need to get the user's location coordinates every 15 minutes roughly and post it to the server. It is necessary to post data roughly at these intervals.
Implementation - I've made a sync adapter instead of using AlarmManager as it saves battery. I've set ContentResolver.addPeriodicSync() to sync my app every 15 minutes roughly which gets the current location and posts to server.
Problem - In case there's no internet connection, I want to continue taking the user's location every 15 minutes and save them in the local sqlite database. When the internet comes back again next time then I'll post all the saved locations in one go so that server data remains consistent and after that sync will resume as normal.
The main problem is that when there's no internet then the sync stops and I stop getting periodic sync callbacks in my app and I'm not able to save data in the local database. So what I want is that even when there's no internet I keep getting callbacks at regular intervals till the internet comes back and auto sync starts again. Can the sync adapter do that?
One solution I can think of is that I get a broadcast when the Internet stops and at that moment I start using the AlarmManager to start a service every 15 minutes and get the location and save to local database. And when the internet comes back on then I stop using the AlarmManager and go back to auto syncing.
Solution 2 - Provided by David Medenjak below. It is also efficient due to AlarmManager's setInexactRepeating() behavior which tries to imitate Sync adapter's behavior by scheduling Alarms for different apps together to reduce the number of times the CPU wakes up. Also it leads to a little simpler implementation. Would this the better way than the previous solution comparing the pros and cons?
Still any better way to achieve this?
You are mixing two things:
Getting the user location every 15 minutes
Syncing the data with the server
If you start mixing those you have a service and sync adapter that are both strongly dependent on each other, you have to check for states which of those has run and which should run. You might end up with the exact thing that you want (syncing every 15 minutes, just cache it if user is offline) but it will be hard to test and maintain.
Always use a service that is run every 15 minutes to store the current user location.
Periodically sync all updates to the server. This may also happen to be every 15 minutes, but you should not depend on this.
By having one part just storing the location and the other part just synchronizing the data you will have a much easier time handling things. And you also don't have to worry about internet connection or the interval of the synchronizations (since sync adapters are not guaranteed to run at exact times).
Concerning battery life (comments)
There should be no big difference whether a SyncAdapter uses gps and posts it immediately or a service persists it for the time being until the adapter syncs it. As soon as a task has to run every x minutes the device will have to wake up.
There might be slight improvements if the synchronization is run at a slower rate compared to the service, since the gps alone might not need any internet connection.
IntentService - runs every 15 min (using AlarmManager) and saves the user location in the db and mark it as unsent.
SyncAdapter - runs every 15 min and ties to send all unsent locations to the server. On success mark the location as sent. Android will make sure it's only run when there is a internet connection.
Edit:
The key point is separating the two sub-tasks (also suggested by #David Medenjak):
1) Get a location update and store it in a db
2) Send the location updates to the server when there is a network connection.
The FusedLocationProvider has a method
requestLocationUpdates (GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)
for when your app is in the background. Link
This method is suited for the background use cases, more specifically
for receiving location updates, even when the app has been killed by
the system.
You can use a LocationRequest to set the priority, interval, power consumption. Link
When you receive the pending intent, you can insert the location in the database and request a sync using the sync adapter.
Related
I am devolping an Android App that need to execute an accumulation of internet tasks periodically (like a web bot). Those tasks need to get stored at a specific time so I thought about using Alarm Manager and a
embeded Database. Due to it, the app could be active much more time, although those save tasks do not need web connection. Later I will throw another Alarm Manager to execute all the tasks queued and do web stuff.
Otherwise I am not sure if it is better to use a foreground service. The app will be working all the day saving the tasks (each 5 or 15 min) but only running task queue with internet each 30mins.
I feel capable of developing both systems but I would like to know which one is better in terms of performance, of battery consumption.
Thank you very much.
Only a recommendation try to find and use a nice library to do it, every Android Update change something about foreground/background servicess.
one is
TimedDog
and for more
enter link description here
Regarding the problematic stated below I have come to a point where I need to make a decision on whether to:
Start a Service once that has an AlarmManager inside which then starts the query every 10 minutes. This Service will only be stopped if the user sets an "Onn-Off" Switch to "Off".
Use an AlarmManager to start an IntentService every 10 Minutes. This Service will then only be started when needed and closed afterwards
Which of these ways is better when it comes to:
- Ability to exchange data received by the Service (Or Intenservice) with other activities/services
- Battery usage
- Overall "good coding habits" ?
Thanks!
Original Question:
I am a pretty new Android Developer and have come across a situation that I do not know how to solve. I have already spent several days searching for a solution but could not find one.
While trying to develop my first app idea I have started playing around with receiving and parsing data from the internet. What I have achieved so far is generating a query that receives JSON data via an API and parses this JSON. All of which is done inside an AsyncTask. The received data is then shown on the screen.
However, for the purpose of my app idea, I need this to be done in the background. What I have thought of is:
Starting a Service that pretty much has the same logic as my Asynctask. Managed by an AlarmManager, this service then requests, receives and parses the data in a specific time interval.
Now the tricky part begins:
The data that I receive (let's say every 10 minutes) shall be used to change an alarm clock. So, as a simple example, let's say the user can set his alarm clock to 08:00 in the morning. The application then checks the current temperature every 10 minutes and changes the alarm clock time to 07:45 if the temperature is below 0° celcius because the user has to wake up earlier to clear the ice off his car.
Also, when "waking up" the application, the current (or rather the latest received) tempereture shall be shown in the UI.
What would be the best way to achieve this? I am having some issues regarding passing/receiving data from AsyncTasks/Services to/from Activities.
My first approach would be to start a single service from the MainActivity, passing some data to the Service (like the initial time the alarm shall start and the current location of the user). The Service then has two seperate AlarmManagers. One of which is set to perform the actual alarm (waking up the user in the morning) and the other manages the time interval of getting the data from the internet.
My questions:
- Does my train of thought make any sense at all so far?
- What is the best way to pass and receive data to/from a service? My best guess would be to use intents to pass and a broadcastreceiver to receive data from the service. would this make sense in this specific situation?
I fear that it is not welcomed to post questions without putting in any effort of your own before. Although I did not add any actual source code, I hope you can see that I have dealt with these questions for quite a while now but could not really start coding before I know the structure of the application.
Thanks in advance
Use AlarmManager to start an IntentService as often as necessary (in your example, it should be sufficient to start checking the temperature about two hours before the user plans to get up and maybe again after one hour and finally half an hour before the normal wakeup time. More often only in case of extreme weather conditions.
It's not necessary to check the temperature exactly at 03:33 a.m. so use
setInexactRepeating(), this will be easier on the battery.
See also Scheduling Repeating Alarms
Write the results to SharedPreferences and have one IntentService check 15 minutes before normal wakeup time if the user should get up right then. Cancel the normal wakeup alarm in this case. Communicating via SharedPreferences (think of a mailbox) and local (!) Broadcasts is a good idea - cheap and secure :)
My application is based on Google Map and Location which includes client-server communications. Apart from all that, periodically I want to update the user location to web server. I gave thought myself and ended up with below two scenarios,
First One :
I use Service class to fetch user location periodically (considering 2-3 hours once) and update to server. Ideally I want to avoid this! Because just to upload user location its not good to run the service all the time is what I feel.
Second Thought :
I can use IntentService to fetch the user location periodically (considering same 2-3 hours) and update to web server. Here IntentService will be invoked by an AlarmManager. That is every 2-3 hours once alarm manager will start IntentService.
But I feel using AlarmManager for 2-3 hours once is not a good idea too.
I want to understand which one will be efficient and more relevant! Whether this scenario can be implemented in any other approach? If so help me do it!
Thanks in advance...
In an Android app, I perform a data poll from server on push. When the device receives a push it pings the server to get the latest data.
As the user base grows, Server could potentially get 1000's of request at the time of push taking the backend down. I am looking for a good alternative so that I can spread out the server call in a given time window say next 2 hours. What is the a good way to do it?
I was looking into GCM Network Manager One-off task. One thing I am not certain is that even if I set a time-window start now with offset of 2 hours, since the device would be connected to the network when the push is received, it would trigger the server call right away defeating the purpose.
Any suggestions on what might be a good way to resolve this?
I don't think the task will execute immediately, as the GCM network manager doesn't execute only when the network is up, but tries to batch jobs together to reduce the number of wakeups and power consumption.
However, to be safe, when you create the OneoffTask, you can set an execution window. There you can set a minimum amount of time before the task will run. I suggest using a random number of seconds, e.g. between 0 and 60 to reduce the potential load on your server.
I want to know what are the best practices for Location-based Android app's architecture/workflow?
My current code uses several Activity and one backing Service, and several AsyncTask.
I start my Service as soon as my app is launched, I do all the HTTP callings and parsings in my Service. And I also wrote a subclass of AsyncTask to obtain user's location. I run the AsyncTask everytime I need to update user's location. The AyncTask calls LocationManager.requestLocationUpdates() and asks to get locations as fast as possible. My strategy for this is:
1. At first, I getLastKnownLocation for both GPS and network, and compare them using the method on http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate.
2. When 3 GPS locations and 5 network locations is obtained, or one or both of GPS and network didn't respond in 1 minute, I stop the task.
3. I return the best estimate I have.
the Locating AsyncTask is run in the Service, and I set an AlarmService for 5 minutes to send my service an Intent to check whether I need to update user's location. My min interval between two AsyncTask is 10 minutes. User is able to request Location updates manually by simply pressing a button.
Above is how I implement the Location service into my app.
I need to know whether my practice is appropriate. If not what is wrong? If yes, is there anything that can be improved?
I think youy pretty much got it. I have very similar solution where I want "in and out" as soon as I can.
I implemented check for "accuracy" into my algoritm. I give service 1 minute from start to get BEST possible location or I will exit even earlier if I get 25m or better accuracy fix.
Also, I don't use AsyncTask for location itself - Service doesn't block thread, it get's and processes callbacks from LocationManager so I don't see why you want to do AsyncTask.
When I'm done with obtaining location and about to exit - then I call async task to process Http post to the server.
As far as interval - I give user options of 5/15/30/1hr and 1/2day. I use inexact alarm for this - supposedly better on battery.
This is not an answer per say , but here are some additional points. Reto Meier , in his Pro Android tips in Google IO suggested not using wi-fi if the battery was low.
This can also be extended to location. Let the user know his battery is too weak & the app wont be using GPS & network provider , instead it will be using the last known location which may be inaccurate.
You have not mentioned it, so I am going on the worst case scenario that you can not checking if the location providers are enabled. You need to check for the same and have an alert asking the user to enable location service if all are providers are disabled.