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
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.
I would like to know the retry interval for DownloadManager.
My downloads get stuck at STATUS_PAUSED status, with the reason PAUSED_WAITING_TO_RETRY. (This is strange because I have no connection problem and it only happens on Android 6 - please see this separate question for further info).
The app eventually retries to commence the download but the delay is way too long, and the interval seems irregular. When does DownloadManager attempt to retry the download? Is there a way to manually trigger the retry?
One way I can think of going about this is:
Keep track of the id returned on DownloadManager.enqueue
Check for status at intervals you desire and DownloadManager.remove if needed
Unfortunately, as far as I can recollect, the automatic retry cannot be triggered manually.
Hope this helps!
I have a broadcast receiver watching the wifi state and sending an http request to me server when it becomes enabled. The problem that I have is that when I run the code under debugger it works just fine, but when I run the same code without a debugger, it throws an exception.
The exception indicates that the failure is actually the DNS resolution failure - it fails to resolve the DNS name.
I decided that even though the system fired the 'enabled' event, the DNS resolver is not fully initialized yet and added a 10sec delay before the attempt to send my request and this resolved the issue, but I am really uncomfortable with this solution. Even though in my case it does not really matter, 10 sec seems too long. A bigger question will 10 sec be enough on all platforms?
Another solution would be to intercept this particular exception and try again. The question is - how many retries?
My question is - what's the best way to wait until the DNS resolver is fully initialized? Is there an event or a notification I can subscribe to?
I have implemented a queue service in Android that will change states based on queue and wifi/data connectivity events.
I queue transactions to be posted to a remote url. If the device has a data or wifi connection, it will iterate the queue and post data to the url until the queue is empty, or there is a disconnect event.
I can login to my app, enable airplane mode, generate data, turn airplane mode off, and the transaction are posted. No slow down, even with thousands of transactions. (I was trying to pish it a bit)
Enter: low reception!
My app slows down enormously when the 3G reception is low. (Yes, all uploading happens off the ui thread.) It seems that the cause of this slow down has to do with the post to the server taking a very long time to happen and sometimes just failing.
My question is, how can I solve this? Check for signal quality? Poll a known address? How do other apps, such as Gmail solve this? This must be a common scenario!
Well if you could potentially have thousands of tasks that all need to be executed, then surely they should be managed. Have you thought about implementing your own ThreadPoolExecutor? The documentation is very good and the class is easy to understand, but if you need examples try these sites:
http://www.javamex.com/tutorials/threads/ThreadPoolExecutor.shtml
http://javabeanz.wordpress.com/2010/02/19/threadpoolexecutor-basics/
The benefit of this is that you can limit the maximum number of threads you are spawning, so you shouldn't get a system-wide slow down if you limit your thread count to a reasonable number (For Android I'd recommend no more than 20).
May be do some fine-tuning of socket and conenction timeout? Thus, if your connection is slow and stalled, timeout will occur and transmission will fail.
After connection/sending is failed you can retry transmission later or do something else.
To adjust timeouts you can use the following code:
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 30 * 1000);
HttpConnectionParams.setSoTimeout(httpParameters, 15 * 1000);
HttpClient client = DefaultHttpClient(httpParameters);
// use client...
We have similar situation for our application. We have considered signal issues to be a reality and one that can happen any time. One of the point that we follow is not to remove any content from device unless we get a functional confirmation from server and just base on http status code.As in the slow network or the cases where we can lose signal suddenly, while we may have posted our content, there were many cases where data was received only partially. And so we decided to let server know device by some manner [result through some http get based request calls made by device] that content has been received.
More than performance or checking the network, the question that you asked, we needed such behavior for our application robustness.
You should check out using HTTP Range headers, for example like here.
The server should write payload to disk while reading, and handle disconnects. The client cannot know how many bytes payload actually reached the server, so it needs to sync up with the server every time there has been a network error. Dont forget to handle battery and user issues too ;-)
If you want to wait for a better signal, perhaps the SignalStrength class, with its getCdmaDbm, getEvdoDbm, and getGsmSignalStrength methods, is what you are looking for.
Check out this:
http://www.youtube.com/watch?v=PwC1OlJo5VM#!
advanced coding tips and tricks, bandwidth-saving techniques, implementation patterns, exposure to some of the lesser-known API features, and insight into how to minimize battery drain by ensuring your app is a good citizen on the carrier network.