To update the GUI from other threads, there are basically two main approaches:
Use java.lang.Runnable with any of these methods:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler.post(Runnable)
Use android.os.Message:
Handler.sendMessage(Message) / Handler.handleMessage(Message)
You can also use AsyncTask, but my question is more focused on the use case of updating a very simple component. Let's see how it would be done using both approaches:
Using Runnables:
TextViev tv = ...;
final String data = "hello";
Runnable r = new Runnable() {
@Override
public void run(){
tv.setText(data);
}
};
//Now call Activity.runOnUiThread(r) or handler.post(r), ...
Using messages:
Message m = handler.obtainMessage(UPDATE_TEXT_VIEW, "hello");
handler.sendMessage(m);
//Now on handler implementation:
@Override
public void handleMessage(Message msg) {
if(msg.what == UPDATE_TEXT_VIEW){
String s = (String) msg.obj;
tv.setText(data);
} ... //other IFs?
}
IMHO, Messages are not the way to go because:
On the other hand, Runnables follow the well known command pattern, and are more programmer-friendly and readable.
So what are the advantages of using Messages over Runnables? Are Messages pushed into the background in modern day Android programming? Is there anything you can do with Messages that can't be done with Runnables?
Thanks in advance.
I would say there is little difference between using a Message
vs a Runnable
. It'll mostly boil down to personal preference. Why? Looking at the source code you'll find that posting a Runnable
uses the same exact messaging mechanism. It simply attaches the Runnable
to a Message
and sends that.
4.4.2 Source Code
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Ref: Grep Code - Handler
Messages
can be reused, so it results in fewer objects created and less GC. You also end up with fewer classes and anonymous types.
One big advantage is that a class sending a Message
to a Handler
doesn't need to know anything about the implementation of that Message
. That can aid in encapsulation depending on where it's used.
Lastly consider the difference in cleanliness between
mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();
vs
final Foo tempFoo = foo;
mHandler.post(new Runnable(){
@Override
public void run(){
doStuff(tempFoo);
}
};
If you have several places where you would have to doStuff()
, the former is MUCH more readable and you'll have less code duplication.
Handler
interface provides much more functionality than runOnUiThread()
, according to docs:
There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in the future
(2) to enqueue an action to be performed on a different thread than your own.
runOnUiThread
does only a subset of (2). ie "enqueue an action to be performed on UI thread"
So IMO unless you need those extra features runOnUiThread
is sufficient and preferred way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With