Why to use Handlers while runOnUiThread does the same?
AndroidMultithreadingAndroid AsynctaskHandlerAndroid Problem Overview
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.
Android Solutions
Solution 1 - Android
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.
Solution 2 - Android
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.
Solution 3 - Android
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
Solution 4 - Android
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).
Solution 5 - Android
>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();
}
}
}