What are Handlers and Runnables for in Android? - android

Please I am blocked with this concept of Handlers and Runnables in Android. Can someone please give me detailed explanation on Handlers and Runnables? Their syntax and implementation? I have read many articles on this but the concepts are not still clear and are even deployed in Java. Thanks in advance

I'm going to try to simplify so bear with me if it is not 100% accurate.
Basically, a Handler is used to communicate with a MessageQueue associated with a Thread.
If you're on the main thread, or if you've called Looper.prepare() in the Thread that you're in, it has a Looper which is basically a holder for the MessageQueue.
This queue is constantly polled so that whenever a Message goes into it, it's dealt with on the Thread associated with this MessageQueue
If you're trying to execute a piece of code on a particular Thread, you have to use a Runnable. It is just an interface that has a void run() method which will be executed by the Looper, on its Thread.
Let's say you're doing a network request, you want it to happen on another Thread but when you get the result you somehow need to pass the data back to the Main Thread in order to update your UI because Views can't be modified from another Thread.
You would do it like so:
// This will let you run method on main thread (even if you're not on main thread)
private final Handler handler = new Handler(Looper.getMainLooper());
// This will let you run method on background thread
private final Executor executor = Executors.newSingleThreadExecutor();
public void doSomething() {
// posting to executor will go to background thread
executor.post(new Runnable() {
#Override
public void run() {
// This will now run on background thread
// you can for example do network request here
// posting to handler will go back to main thread
handler.post(new Runnable() {
#Override
public void run() {
// This will execute on the Main Thread
}
});
}
});
}

Related

What is the difference between these methods for running code on UI Thread?

There are different methods posted on the web on how to run code on the UI thread. They all accomplish the same task, however, I really want to know the difference between these methods.
Method 1:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 2:
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 3:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
In Android, a Thread might have one Looper or MessageQueue. Handler is used to send Message or post Runnable to MessageQueue of a Thread, and it must always be associated with a Looper or a MessageQueue of a Thread.
Method 1
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
When open an app, Android create a new thread (called main thread or UI thread) with a Looper and MessageQueue, this thread is used to render UI and process input events from users.
The above code is create a Handler and associated with Looper of UI thread, so the runnable will be queued to MessageQueue of UI thread, and will be executed later.
Method 2
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Creating a Handler and associated with Looper of current thread, there are 3 cases:
If this code is executed on UI thread, then the runnable will be queued to MessageQueue of UI thread and will be executed later.
If this code is executed on a background thread, if this thread has a Looper, then the runnable will be queued to MessageQueue of background thread and will be executed later.
If this code is executed on a background thread and this thread has no Looper, then an exception will be thrown.
Method 3
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
runOnUiThread is just a utility method of Activity, it used when you want to execute some code on UI thread. The logic behind this method is if current thread is UI thread, then execute it immediately, otherwise used Handler to post a message to MessageQueue of UI thread (like method 1).
Method 1 will always work.
Method 2 will only work if you're already on the UI thread- the new Handler without a Looper parameter creates a Handler to the current thread (and fails if there is no Looper on the current thread).
Method 3 needs to be done in an Activity or called on an Activity object, as runOnUiThread is a function of Activity. But under the hood it will do the same as 1 (although probably keeps a single Handler around to be more efficient, rather than always new-ing one).
All methods works like this:
Method 1 looping handler if loop exist
Method 2 handler can works in all activities if not private or wanted
Method 3 handler can work only in current activity

Usage of a handler

I'm recently getting involved in some concurrent programming specially with Java and Android.
I have some questions regarding Handlers.
1 - It is known that we need to associate a Handler with a thread, and it will run on the thread it was invoked on. However, in some examples on SO, the user is doing
public class MainActivity extends Activity
{
private Handler handler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState)
{
handler.postDelayed(runnable, 1000);
}
private Runnable runnable = new Runnable()
{
public void run()
{
//Do whatever
handler.postDelayed(this, 30000);
}
};
In this example, I assume we are doing the Handler thing on the UI Thread, RIGHT ?
Can I do a network operation here in place of //DO Whatever ? I don't think so, because we are on the main thread.
Is doing this pointless ? As one may use AsyncTask to replace this task ?
How can I apply this same example but not on the UI thread, rather a seperate thread ?
Do thread or Runnables have something similar to post delayed ?
Is it common to use the handler just for its postdelayed feature and not the main task handlers are made for, ie, being the middle man between the thread and the UI/Activity ?
Handlers are useful only when you want update UI. As you may know we cannot update UI from non UI Thread. If you are going to do some network stuff in background thread, and then update UI, you have to use Handler class or AsyncTask or you can do like this:
(from non UI Thread)
SomeView.post(new Runnable() {
//updating UI
});
If whatever you are doing is "heavy" you should be doing it in a Thread. If you do not explicitly start it in its own thread, then it will run on the main (UI) thread which may be noticeable as jittery or slow to respond interface by your users.
Interestingly when you are using a thread it is often useful to also use a Handler as a means of communication between the work thread that you are starting and the main thread.
A typical Thread/Handler interaction might look something like this:
Handler h = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 0){
updateUI();
}else{
showErrorDialog();
}
}};
Thread t = new Thread() {
#Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler and it will do it for us.
h.sendEmptyMessage(0);
}else{
h.sendEmptyMessage(1);
}
} };
In general though, the take home is that you should use a Thread any time you are doing some work that could be long running or very intensive (i.e. anything network, file IO, heavy arithmatic, etc).

How to keep thread alive without blocking app?

In order to execute some IO operations in my app I wrote a thread, there's nothing on its run method but it has several other methods, like void write(String filename, String data) and void create(String filename), all of which work like a charm. My question is, I used to think this thread was running on the background or something like this but since after removing the .run() statement on my main activity calling said methods still works, how can I have a thread running and waiting for a message from the activity without blocking the app? And second question, since the methods are still working does it mean they are being executed on the main UI thread when I call them from my main activity?
You should use the start() method, instead of the run().
With run() you are running the given Runnable in the calling thread.
With start() you are starting a new thread that handles this Runnable
For the methods to run on the said thread you will have to have to call your methods from the thread and not from any other thread.
class WorkerThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Then use WorkerThread.mHandler.postRunnable or sendMesssage for the work to be done on another thread.
In order to make a que for processing stuff when delivered, you need to make use of android's native stuff which is the best option available:
HandlerThread
Looper
Handler
Message
For examples, read this and this.

What's the android preferable way of spawning a new thread?

Coming from the basic Java world I know there's a way to spawn a thread by creating a new Runnable and passing it to a new Thread and calling start on it. Something like:
Runnable r = new Runnable() {
#Override
public void run(){
}
}
new Thread( r ).start()
Now joining the Android world it seems the Android eco system provides a few other ways to spawn a thread. One of them is Activity.runOnUiThread (for having stuff done on the UI) and Handler.post( runnable ).
What I am wondering about is what's the Android preferable way of spawning a new thread. I do see a lot cases such as:
Handler handler = new Handler()
handler.post( r )
Is there a good reason to use Handler to spawn a thread as opposed to creating a new Thread old way?
Thanks.
Yev
Check out the AysncTask framework. It seems like that's how Google wants you to handle threads...although you can use standard java threading.
The Handler in the way you've demonstrated doesn't actually spawn a new thread. Handlers are not threads, but are rather a means of IPC to let one thread tell another thread to run code. You still spawn off threads in the same old way, but the Handler helps those threads communicate better.
Say, for example, you have a Thread that you've spawned off in the background in the usual way:
Runnable r = new Runnable() {
#Override
public void run(){
}
}
new Thread( r ).start()
It runs in the background doing processing, but it needs to update the UI with it's progress, so it calls back to the Activity:
onProgress(int progress) {
// update UI
}
If you run that code as is, it will throw an exception, because only the UI thread is allowed to update the UI. Handlers can solve that problem like so:
public void onProgress(int results) {
mHandler.post(new UIUpdater(results));
}
private class UIUpdater implements Runnable {
UIUpdater(int results) {
//construct whatever...
}
#Override
public void run() {
//Update UI
}
}
Alternately, you can have Android manage Threads and Handlers for you through the AsyncTask framework
Handler is not supposed to spawn thread , but to post new task to UI thread. IMO the way to spawn thread is the java way, through runnable or extended thread directly. The android guys wrapped an Executor around the Async task and exposed some method that run directly in UI thread, and one to run your task in background.

Specifics on using Looper.prepare() in Android

I'm having a bit of trouble understanding how to use the Looper prepare()/loop()/quit() logic.
I have three threads: one is the UI thread, one is a game logic thread and the last is a network communication thread (a background thread, lives only while being used).
The game thread has many dependencies on the results of the network calls, so I wanted to spin the network thread off of the game thread and have a Handler post the result back.
Of course, since the UI thread is not involved I need to call Looper.prepare()... somewhere. I thought it should be called in the game thread, but I can't do that because loop() takes it over.
How do I go about posting back to the game thread from network thread with my handler?
What's going on is that once you call Looper.prepare() followed by Looper.loop() on a Thread, all that Thread will ever do is service its MessageQueue until someone calls quit() on its Looper.
The other thing to realize is that, by default, when a Handler is instantiated, it's code will always execute on the Thread it was created on
What you should do is create a new Thread and in run() call Looper.prepare(), setup any Handlers, and then call Looper.loop().
Bearing these things in mind here is the basic pattern I use a lot of places. Also, there's a good chance you should just be using AsyncTask instead.
public class NetworkThread extends Thread {
private Handler mHandler;
private Handler mCallback;
private int QUIT = 0;
private int DOWNLOAD_FILE = 1;
public NetworkThread(Handler onDownloaded) {
mCallback = onDownloaded;
}
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
// things that this thread should do
case QUIT:
Looper.myLooper().quit();
break;
case DOWNLOAD_FILE:
// download the file
mCallback.sendMessage(/*result is ready*/);
}
}
}
Looper.loop();
}
public void stopWorking() {
// construct message to send to mHandler that causes it to call
// Looper.myLooper().quit
}
public void downloadFile(String url) {
// construct a message to send to mHandler that will cause it to
// download the file
}
}
Could you tell some examples for what you are using your network thread? I think you can solve your problems without using Looper.
You can use ASyncTask to perform background task that may update some values in your UI thread. If user has to wait until background operation will be finished, you can show ProgressDialog and block application in OnPreExecute method, and then hide it in onPostExecute.
As I said, please describe more your needs and target which you want to achieve.

Categories

Resources