handler.postDelayed vs. AlarmManager vs - android

I have a minor problem in one of my apps. It uses a BroadCastReceiver to detect when a call finishes and then performs some minor housekeeping tasks. These have to be delayed for a few seconds, to allow the user to see some data and to ensure that the call log has been updated. I'm currently using handler.postDelayed() for this purpose:
public class CallEndReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (DebugFlags.LOG_OUTGOING)
Log.v("CallState changed "
+ intent.getStringExtra(TelephonyManager.EXTRA_STATE));
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE)
.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
SharedPreferences prefs = Utils.getPreferences(context);
if (prefs.getBoolean("auto_cancel_notification", true)) {
if (DebugFlags.LOG_OUTGOING)
Log.v("Posting Handler to remove Notification ");
final Handler mHandler = new Handler();
final Runnable mCancelNotification = new Runnable() {
public void run() {
NotificationManager notificationMgr = (NotificationManager) context
.getSystemService(Service.NOTIFICATION_SERVICE);
notificationMgr.cancel(12443);
if (DebugFlags.LOG_OUTGOING)
Log.v("Removing Notification ");
}
};
mHandler.postDelayed(mCancelNotification, 4000);
}
final Handler updateHandler = new Handler();
final Runnable mUpdate = new Runnable() {
public void run() {
if (DebugFlags.LOG_OUTGOING)
Log.v("Starting updateService");
Intent newBackgroundService = new Intent(context,
CallLogUpdateService.class);
context.startService(newBackgroundService);
}
};
updateHandler.postDelayed(mUpdate, 5000);
if (DebugFlags.TRACE_OUTGOING)
Debug.stopMethodTracing();
try
{
// Stopping old Service
Intent backgroundService = new Intent(context,
NetworkCheckService.class);
context.stopService(backgroundService);
context.unregisterReceiver(this);
}
catch(Exception e)
{
Log.e("Fehler beim Entfernen des Receivers", e);
}
}
}
}
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
Maybe there is a better way to ensure that all messages have been processed before a thread dies or another way to delay the execution of those two bits of code.
Thank you

I'm currently using handler.postDelayed() for this purpose:
That's not a good idea, assuming the BroadcastReceiver is being triggered by a filter in the manifest.
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
More accurately, the process is terminated, taking everything with it.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
It's not that bad. Another possibility is to do your delayed work in an IntentService -- triggered via a call to startService() -- and have it sleep on its background thread for a couple of seconds.

Let's try a new way of doing this. Using RxJava. It's much simpler to prototype and easier to manage lots of threads if you want to ever run hundreds of such delayed tasks concurrently, sequentially, coupled with async tasks, chained with synchronous chained async calls etc.
Firstly, set up the Subscriber. Remember new on Subscriber should be done only once to avoid memory leaks.
// Set up a subscriber once
private Subscuber<Long> delaySubscriber = new Subscuber<Long> () {
#Override
public void onCompleted() {
//Wrap up things as onCompleted is called once onNext() is over
}
#Override
public void onError(Throwable e) {
//Keep an eye open for this. If onCompleted is not called, it means onError has been called. Make sure to override this method
}
#Override
public void onNext(Long aLong) {
// aLong will be from 0 to 1000
// Yuor code logic goes here
// If you want to run this code just once, just add a counter and call onComplete when the counter runs the first time
}
}
The snippet below will just emit the 1 in the onNext() of the subscriber.
Note that this is done on the Computation Threadpool created and managed by the RxJava library.
//Now when you want to start running your piece of cade, define an Observable interval that'll emit every second
private Observable<Long> runThisAfterDelay = Observable.just(1).delay(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
// Subscribe to begin the emissions.
runThisAfterDelay.subscribe(delaySubscriber);
If you want to run a code after every one second, say, then you can do this:
private Observable<Long> runThisOnInterval = Observable.interval(1000, TimeUnit.MILLISECONDS, Schedulers.computation());

In addition to the first answer, you might want to consider what the API documentation says for the onReceive method:
[...] The function is normally called within the main thread of its process, so you should never perform long-running operations in it [...]
So it looks like generally it is not a good idea to start something that waits a couple of time within onReceive (even though, in your case it's less than the 10s limit).
I had a similar timinig problem with the BroadcastReceiver. I couldn't get my results processed even though I onReceive had been called with exactly what I was exepcting. It seemed that the thread the BroadastReceiver was running in, got killed before my result processing could finish. My solutuion was to kick off a new thread to perform all processing.

AlarmManager seems not to work very well for short periods of time like 10 seconds and according to user reports the behaviour heavily depends on the firmware.
At the end I decided to use Handler and Runnable in my service.
When creating the Handler, be sure to create it inside the Service class, not inside the BroadcastReceiver since in the last case you'll get Can't create Handler inside thread that has not called Looper.prepare()
public class NLService extends NotificationListenerService {
private NLServiceReceiver nlservicereciver;
Handler delayUpdateHandler = new Handler();
private Runnable runBroadcastUpdate;
public void triggerViewUpdate() {
/* Accumulate view updates for faster, resource saving operation.
Delay the update by some milliseconds.
And if there was pending update, remove it and plan new update.
*/
if (runBroadcastUpdate != null) {
delayUpdateHandler.removeCallbacks(runBroadcastUpdate);
}
runBroadcastUpdate = new Runnable() {
public void run() {
// Do the work here; execution is delayed
}
};
delayUpdateHandler.postDelayed(runBroadcastUpdate, 300);
}
class NLServiceReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
triggerViewUpdate();
}
}
}

Related

Stopping a Handler Thread

On one of our applications, we use a background service with a notification (basically a foreground service but you get the idea, activity is closeable while the service stays alive.)
On this service, we use 3 separate HandlerThreads with Handlers to manage various operations with some delay (for example, 250 milliseconds). Now, these actions need to be stopped if the screen goes off and be resumed if the screen goes back on, due to this situation we added a broadcast receiver to the service, and created-deleted threads. Everything works fine so far.
In order to stop the operations, we deleted the messages on handlers by calling Handler.removeCallbacksAndMessages(null) and it actually clears the message queue. However, the handler thread stays alive. And this is a problem.
In order to stop the thread we used HandlerThread.quit() which internally calls Looper.quit() that we thought, that it will finish the thread, but no sir, it does not delete the thread because we get some reports from Fabric that goes pthread_create failed (1040kb stack), try again or something. Under it, there were 940 separate threads that named the same, which caused a OOM (Out Of Memory) error. This was a huge mistake from us.
The question: How can we stop the handler threads? Is HandlerThread.interrupt() will be enough? Any help is appreciated, thanks. PS: I cannot share any source codes, and in this situation I don't think it is necessary since the question itself is self-explanatory.
Edit: Since you asked for some code, I'm showing an example of some logic I'm following.
public class ThreadHelper implements Runnable
{
private HandlerThread handlerThread = new HandlerThread("ThreadName");
private Handler handler;
private boolean shouldRun = true;
public ThreadHelper()
{
handlerThread.start();
startThread();
}
// Called if the screen state is turned on.
public void startThread()
{
if (handlerThread == null)
{
handlerThread = new HandlerThread("ThreadName");
handlerThread.start();
}
if (handler == null)
{
handler = new Handler(handlerThread.getLooper());
handler.post(this);
}
}
// Called if the screen state is turned off.
public void stopThread()
{
shouldRun = false;
handler.removeCallbacksAndMessages(null);
handlerThread.quit();
try
{
handlerThread.interrupt();
}
catch (Exception ignored)
{
// Skipped Thread.currentThread().interrupt() check here since this is
// called from a different thread that is not associated.
}
// remove variables.
handler = null;
handlerThread = null;
}
#Override
public void run()
{
if (shouldRun)
{
// rest of the code without having a long-running
// operation. Mostly ends in 1~2 millseconds.
// Continue looping.
handler.postDelayed(this, 250);
}
}
}

Thread.sleep() vs handler.postDelay() to execute network call in every 30sec

I want perform a network call in every 30sec to push some metrics to Server. Currently I am doing it using thread.sleep(). I found some articles saying thread.sleep() has some drawbacks. I need to know am I doing it right? or Replacing the thread with Handler will improve my code?
public static void startSending(final Context con) {
if (running) return;
running = true;
threadToSendUXMetrics = new Thread(new Runnable() {
#Override
public void run() {
do {
try {
Thread.sleep(AugmedixConstants.glassLogsPushInterval);
} catch (InterruptedException e) {
mLogger.error(interrupt_exception + e.getMessage());
}
// to do to send each time, should have some sleep code
if (AugmedixConstants.WEBAPP_URL.equals(AugmedixConstants.EMPTY_STRING)||!StatsNetworkChecker.checkIsConnected(con)) {
Utility.populateNetworkStat();
mLogger.error(may_be_provider_not_login_yet);
} else
sendUXMetrics();
} while (running);
if (!uxMetricsQueue.isEmpty()) sendUXMetrics();
}
});
threadToSendUXMetrics.start();
}
If You are using only one thread in the network, then usage of the thread.sleep() is fine. If there are multiple threads in synchronization, then the thread.sleep() command will block all the other threads that are currently running.
As per the details you've provided, there is only one thread present which isn't blocking any other active threads which are running in synchronization, so using thread.sleep() shouldn't be a problem.
Use Handler.postDelayed to schedule tasks if you are working in UI Thread and Thread.sleep if you are working in background thread.
Apparently you are sending some data using network, you must do it in the background thread, hence Thread.sleep is recommended.
Simple is:
Thread.sleep(millisSeconds): With this method, you only can call in background tasks, for example in AsyncTask::doInBackground(), you can call to delay actions after that. RECOMMENDED CALL THIS METHOD IN BACKGROUND THREAD.
Handler().postDelayed({METHOD}, millisSeconds): With this instance, METHOD will trigged after millisSeconds declared.
But, to easy handle life cycle of Handler(), you need to declare a Handler() instance, with a Runnable instance. For example, when your Activity has paused or you just no need call that method again, you can remove callback from Handler(). Below is example:
public class MainActivity extends Activity {
private Handler mHandler = Handler();
public void onStart(...) {
super.onStart(...)
this.mHandler.postDelayed(this.foo, 1000)
}
public void onPaused(...) {
this.mHandler.removeCallback(this.foo)
super.onPaused(...)
}
private Runnable foo = new Runnable() {
#Override
public void run() {
// your code will call after 1 second when activity start
// end remove callback when activity paused
// continue call...
mHandler.postDelayed(foo, 1000)
}
}
}
The code above just for reference, I type by hand because don't have IDE to write then copy paste.

How to correctly use a Workerthread?

I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}

How to implement a more flexible AsyncTask?

while it is very convenient to use, from my understanding, AsyncTask has two important limitations:
doInBackground of any instances will share the same worker
thread, i.e. one long running AsyncTasks can block all others.
execute, onPostExecute and other "synchronizing" methods must/will always be executed on the UI-thread, i.e. not on the Thread, which wants to start the task.
I ran into trouble, when I tried to reuse some existing AsyncTasks in a background IntentService that are responsible for the client-server communication of my app. The tasks of the service would fight over time in the worker thread with those of the UI activities. Also they would force the service to fall back onto the UI-thread, although that service should perform its work quietly in the background.
How would I go about removing/circumventing these limitations? I basically want to achieve:
A framework that closely resembles AsyncTask (because I need to migrate a lot of critical code there).
Each instance of such a task should run its doInBackground on its own thread instead of a single worker thread for all instances.
Edit: Thx to VinceFR for pointing out this can be achieved by simply calling executeOnExecutor instead of execute.
The callbacks like onPostExecute should be called on the same thread that started the task by calling execute, which should not need to be the UI-thread.
I figure, I'm not the first person to require something like this. Therefore I wonder: Is there already some third-party library that can be recommended to accomplish this? If not, what would be a way to implement this?
Thanks in advance!
The solution looks like this:
All classes that spawn AsyncTasks that might interfere with each other get their own Executor like this one (make that elaborate as you like using thread pools etc.):
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
As pointed out by VinceFR you can run an AsyncTask on a given Executor by calling it like this (where payload are the parameters that you would regularly pass to a task):
task.executeOnExecutor(serviceExecutor, payload);
However, this breaks backwards-compatibility to Gingerbread and earlier. Also, if you want to support Honeycomb, you need to make sure, this call happens on the UI thread. Jelly Bean will take care of this automatically.
Now the trickier part: Keeping the service running on its own thread. As many things in Android this seems harder than it needs to be (or maybe I'm lacking some information here). You can't use an IntentService, because that will shut down automatically the first time an AsyncTask takes over and let's the onHandleIntent callback complete.
You need to setup your own thread and event loop on the service:
public class AsyncService extends Service {
private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
public Handler threadHandler = null;
public void run() {
Looper.prepare();
this.threadHandler = new Handler();
Looper.loop();
}
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;
#Override
// This happens on the UI thread
public void onCreate() {
super.onCreate();
}
#Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
this.serviceThread = new LooperThread();
this.serviceThread.start();
while(this.serviceThread.threadHandler == null) {
Log.d(TAG, "Waiting for service thread to start...");
}
this.serviceThreadHandler = this.serviceThread.threadHandler;
this.serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheFirstThingOnTheServiceThread();
}
});
return Service.START_STICKY;
}
// doTheFirstThingOnTheServiceThread
}
No you need to make sure that each time an AsyncTask returns to the UI thread, you end up in your service thread instead:
// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
// do some stuff
// here we can reuse a class that performs some work on an AsyncTask
ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
// the existing class performs some work on an AsyncTask and reports back via an observer interface
someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
#Override
// This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
public void onOperationComplete() {
serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheSecondThingOnTheServiceThread();
}
});
}
}
someUsefulObject.performOperation();
}
// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
// continue working on the serviceThread
}
So, this works for me. I'd be delighted to see a simpler solution for this. Note that the solution requires the service to know that is will be called back by the ExistingClassWithAsyncOperation on the UI thread. I don't particularly like this dependency, but don't know how to do better right now. However, I don't have to rewrite a lot of existing classes that perform asynchronous operations using AsyncTask.

Threading and Message Handling in an Android Service

I have a service, that when starting, fires up a thread which is supposed to be the "main thread" of the service. The service is bound to two other services which is part of a library that I'm using. In this thread, I want to handle messages that is sent to the service from the services it is bound to (because this is how it works with binding... right?). The binding goes well (returns true) but my problem is that I can't seem to receive any messages at all. A description of my setup follows:
The Service:
class MyService extends Service {
onCreate(...) {
myServiceApp = new MyServiceApp(this);
}
onStartCommand(...) {
Thread thread = new Thread(myServiceApp);
thread.start();
}
}
The Main Thread Class:
class MyServiceApp() {
private Service service;
final Handler mHandler = new Handler() {
void handleMessage(Message msg) {
...
}
};
void run() {
boolean as = service.bindService(new Intent(...), ..., Context.BIND_AUTO_CREATE));
boolean ctrl = service.bindService(new Intent(...), ..., Context.BIND_AUTO_CREATE));
Looper.prepare();
while(true) {
...
}
}
}
Now, I know that to be able to declare a handler like this, I need a message loop for the thread, so I call prepare() in the run method. I also felt like I need to run through the message loop every turn in my while loop, so I added a Looper.loop() there, but that just made the application hang on that line.
So my question is, how do I solve the problem and have the messages delivered where I want? I'm aware of that my app architecture might not be optimal, so feel free to give suggestions on how to improve it.

Categories

Resources