59

I have come across both Handlers and runOnUiThread concepts. But to me it still seems to be a doubt as on which facts do they differ exactly.

They both are intended to do UI actions from a background thread. But what are the factors that are to be considered while we choose among the two methods.

For example consider a Runnable Thread which performs a web service in the background and now I want to update the UI.

What would be the best way to update my UI? Should I go for Handler or runOnUiThread?

I still know I could use a AsyncTask and make use of onPostExecute. But I just want to know the difference.

rene
  • 41,474
  • 78
  • 114
  • 152
Andro Selva
  • 53,910
  • 52
  • 193
  • 240
  • 5
    `runOnUiThread` is just a shortcut for posting a `Runnable` to a `Handler`. `Handler` is the base of every(?) cross-thread-communication facility defined by Android (e.g. `AsyncTask`'s `onPostExecute` uses a `Handler` to deliver the result from `doInBackground`). – zapl Sep 27 '12 at 09:43

5 Answers5

85

Activity.runOnUiThread() is a special case of more generic Handlers. With Handler you can create your own event query within your own thread. Using Handlers instantiated with the default constructor doesn't mean "code will run on UI thread" in general. By default, handlers are bound to the Thread from which they were instantiated from.

To create a Handler that is guaranteed to bind to the UI (main) thread, you should create a Handler object bound to Main Looper like this:

Handler mHandler = new Handler(Looper.getMainLooper());

Moreover, if you check the implementation of the runOnUiThread() method, it is using Handler to do the things:

  public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

As you can see from code snippet above, Runnable action will be executed immediately if runOnUiThread() is called from the UI thread. Otherwise, it will post it to the Handler, which will be executed at some point later.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
HitOdessit
  • 7,198
  • 4
  • 36
  • 59
  • But doesn't "Thread from which they was instantiated from." usually the UI thread? – SIr Codealot Apr 28 '13 at 21:53
  • 9
    @Mike, this is totally depends from your code. Often yes, Handlers are instantiated from main thread, but there are lots of cases where developer doesn't have exact information about current thread when creating `Handler` instance. Therefore, developer should use `new Handler(Looper.getMainLooper())` if he needs guaranties that handler will perform in main thread. – HitOdessit Apr 29 '13 at 07:59
  • @Hit thanks a lot, your `Looper.getMainLooper()` phrase gave me a great help in a non-making sense problem i had, (http://stackoverflow.com/questions/22831612/cant-handle-ui-after-reconnecting-to-the-server) – Muhammed Refaat Apr 03 '14 at 10:12
  • Also note that `runOnUiThread()` will run the `action` immediately if `runOnUiThread()` is called from the UI thread. Otherwise, it will post it to the Handler. – Ken Jul 09 '14 at 18:38
1

Handlers were the old way (API Level 1) of doing stuff, and then AsycTask (API Level 3) were introduced, along with a stronger focus on using runOnUIThread (API Level 1). You should avoid using handlers as much as possible, and prefer the other two depending on your need.

Animesh
  • 1,765
  • 2
  • 22
  • 36
  • 1
    But why? I need the difference exactly. Can you please explain more. – Andro Selva Sep 27 '12 at 09:25
  • There is no difference, you can achieve the same things with Handlers and Loopers, but these techniques help you avoid mistakes. See http://en.wikipedia.org/wiki/Syntactic_sugar – Animesh Sep 27 '12 at 09:28
1

Handler have many work like message passing and frequent UI update if you start A Thread for any running a task .A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue ,, which is very useful in many application like bluetooth chat ,, wifi chat ... and handler has as Method PostDelay and PostAtTime by which you can play around any view to animate and change visibility and so on

You must look in this

http://developer.android.com/guide/components/processes-and-threads.html

http://developer.android.com/tools/testing/activity_testing.html

Vipin Sahu
  • 1,441
  • 1
  • 18
  • 29
  • 1
    runOnUIThread always do computation on UI thread , While Using Handler U can fire off a Thread to do heavy computation there and post the result to UI thread Using Handler. So If u use runOnUIThread ,then be careful dont do heavy computation on it.Async too use Hanlder inside to post update and progress. it better depend on ur easy of use. – Vipin Sahu Sep 23 '13 at 05:44
1

Following HitOdessit's answer.

You can create a class like this.

public class Global{
    private static Handler mHandler = new Handler(Looper.getMainLooper());
    public static void runOnUiThread(Runnable action){
        mHandler.post(action);
    }
}

And then call it like this.

Global.runOnUiThread(new Runnable(){
    //Your code
});

And this can be run from anywhere (where you have access to your Global class).

  • 1
    This is just syntactical sugar. there is no need to make handler's object private or even in a different class at all, imho. – ansh sachdeva May 30 '19 at 00:48
1

What would be the best way to update my UI? Should I go for Handler or runOnUiThread?

If your Runnable needs to update UI, post it on runOnUiThread.

But it's not always possible to post Runnable on UI Thread.

Think of scenario, where you want need to execute Network/IO operation Or invoke a web service. In this case, you can't post Runnable to UI Thread. It will throw android.os.NetworkOnMainThreadException

These type of Runnable should run on different thread like HandlerThread. After completing your operation, you can post result back to UI Thread by using Handler, which has been associated with UI Thread.

public void onClick(View view) {

    // onClick on some UI control, perform Network or IO operation

    /* Create HandlerThread to run Network or IO operations */
    HandlerThread handlerThread = new HandlerThread("NetworkOperation");
    handlerThread.start();

    /* Create a Handler for HandlerThread to post Runnable object */
    Handler requestHandler = new Handler(handlerThread.getLooper());

   /* Create one Handler on UI Thread to process message posted by different thread */

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    NetworkRunnable r1 = new NetworkRunnable("http://www.google.com/",responseHandler);
    NetworkRunnable r2 = new NetworkRunnable("http://in.rediff.com/",responseHandler);
    requestHandler.post(r1);
    requestHandler.post(r2);

}

class NetworkRunnable implements Runnable{
    String url;
    Handler uiHandler;

    public NetworkRunnable(String url,Handler uiHandler){
        this.url = url;
        this.uiHandler=uiHandler;
    }
    public void run(){
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL(url);
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());

            Message msg = new Message();

            msg.obj = text.toString();

            /* Send result back to UI Thread Handler */
            uiHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
}
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211