Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delayed Events on Android

Tags:

android

timer

I'm writing an Android app that schedules certain methods to fire at irregular intervals. As far as I know, there are at least two ways to do this:

  1. use Handler.postDelayed to execute a Runnable after a given time.

  2. use a Timer to schedule and execute a TimerTask after a given time.

I'm looking for a solution that can handle multiple events firing in quick succession. Which is the best method to use? Is there a better one I'm missing?

like image 570
Jeffrey Avatar asked Jul 09 '11 05:07

Jeffrey


2 Answers

Short answer

The differ in how they work in the background, using the wrong one can have dire consequences.

All messages and runnables sent to a handler is run on the same thread as the one that created the handler, often a service or activity thread.

Timer on the other hand spawns a new thread.

Sounds to me like Timer is the way to go for you but it is impossible to say for sure with the information given.
It all boils down to if you want everything to be run on one thread or multiple threads, both has it's advantages and disadvantages.

Long answer

Handlers

From the Handler documentation:

Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

This means that only one event can be handled simultaneously with the handler and all other messages/runnables need to wait while another one is executing.
Handler is however the only way to go if you want to manipulate the UI as only the main UI thread is allowed to do so.

Using handlers can result in your application freezing if you don't take care.
A common mistake is when people create a handler on the main UI thread, spawn a bunch of worker threads and call heavy methods using handlers, this will cause the main UI thread to lock up and will make the dreaded "The application is not responding" dialog in android

That said handlers can be great for dealing with thread safety, you can make every thread have a handler which handles all cross thread calls (using messages) and if you make sure only the handler modifies an object you will never have threading issues.

Timers

With timers however you get the overhead or creating threads and the added complexity of threading, be careful when modifying shared objects!

The advantage is concurrency, if multiple tasks needs to be run simultaneously (or in very short interval) handlers might not be able to handle it whereas timers will.

Other options

  • You might be able to use DelayQueue
  • If you want to allow the phone to sleep and have longer delays use AlarmManager
like image 99
Nicklas A. Avatar answered Sep 24 '22 10:09

Nicklas A.


I used the Timer to delay the event process, during the delay period, the newer comming event will override the older one. So that the onTextChanged events will not be process too many times when user enter text quick enough.

EditText editor_
Timer editorTimer_

editor_.addTextChangedListener(new TextWatcher()
{
    @Override
    public void onTextChanged(final CharSequence s, int start, int before, int count)
    {
        try
        {
            /* events absorber technique */

            if (editorTimer_!=null) 
            {
                editorTimer_.cancel(); //dump the timer to cancel the previous onTextChange firing
            }

            //the timer is dumped, we must to create a new one
            editorTimer_ = new Timer();

            //schedule a task which will be executed in 500ms if the timer won't canceled due 
            //to other (possible future) onTextChanged event

            editorTimer_.schedule(new TimerTask()  
            {
                @Override
                public void run()
                {
                    try
                    {
                        /*
                         * do whatever onTextChanged event have to do. But it should be quick 
                         * heavy process must be executed on other thread  
                         */

                        if (TextUtils.isEmpty(s))
                        {
                            ...
                        }
                        else
                        {
                            ...
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.w(TAG, ex.toString());
                    }
                }
            }, 500); //the 500ms delay is here
        }
        catch (Exception ex)
        {
            Log.w(TAG, ex.toString());
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after)
    {
    }

    @Override
    public void afterTextChanged(Editable s)
    {
    }
});
like image 45
Hiep Avatar answered Sep 23 '22 10:09

Hiep