Handler does not work reliably in Android - android

I have programmed an app which uses a handler. Inside the handler there are some network operations.
The handler has an interval of min*1000*60 ms. I used the handler with min=5, so it should repeat after five minutes. But this is the result of my check:
First Handler:
16:20:22
16:25:23
17:01:52
17:13:07
17:20:19
17:25:55
Second Handler:
16:20:26
16:25:26
17:01:35
17:12:51
17:20:02
17:25:37
Third Handler:
16:24:58
16:31:59
17:12:43
17:19:54
17:25:30
All Handlers are running in separate Services. The screen is turned off.
Do you have any ideas or alternatives to a Handler in Android?
The code of the handlers is so simple:
handler.postDelayed(new Runnable() {
public void run() {
// network operations
}
}, interval);

First, assuming that you created your Handler via new Handler(), it will do its work on the main application thread. Do not do network I/O on the main application thread. It also is likely the source of your drift.
Second, most likely you do not need three services. Usually, you need one service. Three services simply makes your app more complicated for no added value to the user.
Third, your Handler will only work while the device is awake, and I do not know whether that is an acceptable limitation or not.
Fourth, using a Handler implies that your service(s) will be running indefinitely, and users do not like this. Only have your services be in memory when they are actively delivering value to the user.
A better way to implement this, therefore, is to use AlarmManager for your scheduled events. If you do not need the events to be processed while the device is asleep, the AlarmManager can directly pass control to your service. Ideally, that would be an IntentService, so that the service will give you a background thread automatically and so that the service will automatically shut itself down when the work is complete.
If you need the events to be processed even while the device is asleep, please give the user control over the event period, including an option of "do not do anything", as waking up the device every 5 minutes to do network I/O will be bad for the battery. Then, use a WakefulBroadcastReceiver or a WakefulIntentService to arrange to have your work be done while keeping the device awake.

Use SheduledThreadPoolExecutor instead of handler.
It has scheduleAtFixedRate function, which does exactly what you need. And no handlers at all)

Related

Android - Send data to the server in every 5 minutes

I have some data in my SQLite database table. When my app starts, I want to send that data to the server every 5 minutes.
When the app is closed, it should stop.
What is the best approach for this?
Should I use Service or IntentService?
Should I use AlarmManager, Handler or any other thing?
I'm aware of my application speed. I don't want to make it slow. What is the effective approach?
If you are only transmitting when the app is in foreground, you can do it with a Handler.
You start the handler in onResume() and cancel it in onPause().
And perform the transmision with an AsyncTask or in a separate thread.
If you need to stransmit in background, you can use a service instead and schedule it with the AlarmManager.
And then start the service from the app's Activity.
I am not sure how IntentService would be used for this.
As you just want to run your process while the app is foreground, then TimerTask or Handler with conjunction to Message or Runable is good. It won't bother much your app's performance. If you ask about the better one from these two I'll say it's Handler. Check the details here in this answer:
https://stackoverflow.com/a/3975337/4128371
But if you want a really good performance then I'll suggest to go with AlarmManager. Otherwise Handler is a good option.
Alarm manager is not precise, an alarm schedule for 5 minutes may be that when the device is sleeping it will be fired at twice or triple the time.
If you want accuracy the device does not have to fall in sleep. ( I know that will shorten battery duration)
If you want to prevent the device to go to sleep you need to launch a foreground Service with a non dismissable Notification. That's the Service has to call startForeground()
While the device is awake both Alarmamanager and Handler + Runnable will be accurate ... I prefer the Handler.

Is it safe to start a new thread in a BroadcastReceiver?

I need to perform a network operation in a BroadcastReceiver.
So far I achieve it by starting a new thread:
#Override
public void onReceive(Context context, Intent intent) {
new Thread(new Runnable() {
public void run() {
// network stuff...
}
}).start();
}
Is there any risk that the process will be killed before the thread is done?
Is it better to use an IntentService instead? Any other better approach?
Is there any risk that the process will be killed before the thread is done?
If this receiver is registered via the manifest, yes.
If this receiver is registered via registerReceiver(), the lifetime of your process will be determined by other running components.
Is it better to use an IntentService instead?
If that work will be over a few milliseconds, IMHO, yes, probably in concert with WakefulBroadcastReceiver.
Any other better approach?
There is a goAsync() option on BroadcastReceiver that gives you a window of time to do work in another thread before triggering an ANR. I avoid this, because it is poorly documented. For example, it does not directly address your question: what is the process importance while this background thread is doing its work? Does this keep the device awake long enough for our work to get done? And so on. I'll use an IntentService or some other form of Service, where I have better understanding of the contract.
It isn't the best idea. The life-cycle of a BroadcastReceiver lasts as long as it takes to finish calling onReceive(), after that it's destroyed. If you were to start running a new thread, there's a chance the BroadcastReceiver would be killed before the thread completes, which would wind up in some unexpected behaviour.
The better option would be to start a background service, like you said.
Here is some practical information from my tests:
The onResume lasts for 10 seconds.
The Thread itself lasts far longer. About 7 minutes on an idle device.
Filling about 450MB of RAM (on a 4GB device) will stop the thread and garbage collect everything.
Reliability is worse if the BroadcastRecevier is triggered while the device is in sleep-mode (by an AlarmManager). Most of the time it runs fine but sometimes it runs hours later when the phone get's unlocked and sometimes it doesn't run at all. (I used a wake lock too but I don't think it made much of a difference.)
This could be worth trying in some cases because from my experience the android specific threading solutions are not very reliable as well. Maybe for something like a widget button that fetches the latest weather forecast...

Repeating IntentService using Timers- is it advisable?

I have an IntentService that downloads data from a server and I would like the IntentService to check for server updates at a certain interval. The following posts however advice against repeating a Service using a Timer - and instead emphasize on using an AlarmManager:
Why doesn't my Service work in Android? (I just want to log something ever 5 seconds)
Android - Service: Repeats only once
Android service stops
From Android's reference manual, an IntentService is described as:
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
The part I don't really understand is why an IntentService (the posts have questions that are directed towards a Service and not an IntentService) is not allowed to execute repetitively using a Timer as it creates its own worker thread for execution. Is it permissible to use a Timer within an IntentService ? Or are AlarmManagers the only solution to periodically execute an IntentService ?
An explanation to this would be most appreciated .
Or are AlarmManagers the only solution to periodically execute an IntentService ?
If you want it to work reliably, yes. Using AlarmManager is also much more friendly to the user.
First, do not have a Service of any form running except when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user. Having a Service running gives your process a bit higher priority than other processes, in terms of what processes get terminated to free up system RAM for future work. Having a Service around unnecessarily -- such as simply watching the clock tick -- hampers the user's ability to multitask well, as you tie up system RAM unnecessarily.
This behavior will cause some users to attack you with task killers, such as swiping your app off the recent-tasks list. This will terminate your process, and therefore your Timer goes away too. Similarly, because too many sloppy developers keep their Service around for a long time, Android will automatically terminate such processes after some time, Service notwithstanding.
Finally, usually one facet of "check for server updates at a certain interval" is that you want this work to occur even if the device goes into sleep mode. With your everlasting-service approach, that will require you to keep the CPU on all the time, using a WakeLock. This will significantly impact the user's battery, causing your app to appear on the Settings app's "battery blame screen". That, in combination with the tying-up-system-RAM "feature", will likely incite some poor ratings for your app.
Instead, by using AlarmManager:
Your IntentService only needs to be running while it is doing its work ("check the server updates"), going away in between these events, so your process can be terminated to free up system RAM for other things that the user is doing
By use of the WakefulBroadcastReceiver or WakefulIntentService patterns, you can wake up the device briefly to do this work, then let the device go back to sleep again, thereby minimizing the impact on the battery

android monitoring apps

I would like to create an Android application with real-time monitoring functions. One monitoring function is to audit the audio flow. The other function is to interact with a peripheral sensor. These monitoring functions can be triggered by others.
Besides, in order to save power consumption, the audio function will be running in a polling mode, i.e. sleep for a certain amount of time and wake for a certain amount of time.
I am considering how to design the Android application.
Whether to design the audio function as a Service or an Activity?
The problem is if it is designed as an Activity, the audio function will be off if screen turns off after a period of time.
How to design the polling function? Use an AlarmManager or a inner-thread with Timer?
My goal is to save the power consumption as much as possible. Thanks.
I would recommend following
a) Use a Service. Activity is short lived entity (it works only while it's on the screen)
b) Make the service foreground (read this: http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification). This will decrease the chance that system will kill your service
c) In the service, start a thread and do everything you need in the thread.
d) If you want execute periodically, just do Thread.sleep() in the thread (when Thread sleeps it doesn't consume CPU cycles).
I believe c) and d) is preferable to AlarmManager.
Here is piece from documentation (http://developer.android.com/reference/android/app/AlarmManager.html) : "Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler."
Since your application running it's better to have some permanently running thread and execute something on it. Generally speaking Handler, HandlerThread, MessageQueue are just convenience classes for more complex message handling and scheduling. It looks like your case is quite simple and usual Thread should be enough.
Concurring with Victor, you definitely want to use a Service, and pin it into memory by calling startForeground()
However I suggest you look into utilizing the built in system Handler ; place your functionality in a Runnable and call mhandler.postDelayed(myRunnable, <some point in future>) ; this will allow the android framework to make the most of power management.
That's a service.
And you may want some extra robustness: the service can be killed and NOT restarted later, even being a foreground service. That will stop your monitoring.
Start your service from the UI. If you want the service to survive device reboot, also start it from a BroadcastReceiver for android.intent.action.BOOT_COMPLETED.
Create a thread in the service as described in other answers here.
Additionally, use Alarm Manager to periodically start your service again. Multiple startService() calls are OK. If already running, the service will keep running. But if it's been forgotten by the system, say, after a series of low resource conditions, it will be restarted now.
Schedule those alarms responsibly: to be a good citizen, set the absolutely minimal frequency. After all, Android had some good reasons to kill the service.
With some services, even more steps may be needed, but in this case this approach seems to be sufficient.

How to shedule a request for location update in Android from a service

this scenario is very common according to the Android documentation but still I don't find a straight solution neither there nor anywhere on the net.
So I have a service that should do something like this:
Register a LocationListener to receive the user location
Once the LocationListener is called - stop listening for a 5 minutes
After 5 minutes start listening again and loop from 1
This is the recommended way to save battery power while listening for the user location.
As a service I have a major problem with step 3.
The only way I found to "wait" for 5 minutes is to schedule a java.util.Timer to execute a TimerTask in 5 minutes and this TimerTask should register the LocationListneres again.
However this does not work because of:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Which is also expected because requestLocationUpdates should be called from a "main" thread.
Ok .. nice... but I don't have a Main thread. I don't have an activity. From the TimerTask I can't send an intent to the service to register my listeners back.
How can I ask my own service to register my listeners again?
This is the recommended way to save battery power while listening for the user location.
Really? The only way that's a good pattern is if you are using AlarmManager for the five-minute delay, so the device falls asleep in between location checks.
The only way I found to "wait" for 5 minutes is to schedule a java.util.Timer to execute a TimerTask in 5 minutes and this TimerTask should register the LocationListneres again.
And that would be a horrible use of battery, because it would mean you would need to keep the device powered on constantly, not allowing it to go to sleep.
I don't have a Main thread
Yes, you do. All processes have a main application thread. onCreate(), onStartCommand(), etc. of a service are called on the main application thread.
I don't have an activity.
Then you better write one, as your app will not work on Android 3.1+ without it. Your app will not run until a user launches one of your activities on Android 3.1+.
How can I ask my own service to register my listeners again?
What you are trying to accomplish is a rather complex problem. Not only do you need to arrange for the device to fall asleep and wake back up again, but you also need to deal with lots of edge cases (e.g., what if no location is available, because the device is in airplane mode or is underground or something?).
I wrote LocationPoller to handle your use case, and another developer forked it to create a more feature-rich implementation.
Whether you use one of these directly or simply examine their implementation, they should be useful to help you understand how to solve this problem. All of the details, though, are well beyond the scope of a StackOverflow answer -- it would take several pages in a book to explain it all.
You can specify the parameter in requeestLocationUpdates() to make it run after a certain time.

Categories

Resources