I have Activity with Handler (UI thread)
I start new Thread and make handler.post(new MyRunnable()) - (new work thread)
Android documentation said about post method: "Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached."
Handler attached to UI thread.
How android can run runnable in the same UI thread without new thread creation?
Is new thread will be created using Runnable from handler.post()?
Or it's only run() method will be called from Runnable subclass?
Here's a rough pseudroidcode example of how to use handlers - I hope it helps :)
class MyActivity extends Activity {
private Handler mHandler = new Handler();
private Runnable updateUI = new Runnable() {
public void run() {
//Do UI changes (or anything that requires UI thread) here
}
};
Button doSomeWorkButton = findSomeView();
public void onCreate() {
doSomeWorkButton.addClickListener(new ClickListener() {
//Someone just clicked the work button!
//This is too much work for the UI thread, so we'll start a new thread.
Thread doSomeWork = new Thread( new Runnable() {
public void run() {
//Work goes here. Werk, werk.
//...
//...
//Job done! Time to update UI...but I'm not the UI thread! :(
//So, let's alert the UI thread:
mHandler.post(updateUI);
//UI thread will eventually call the run() method of the "updateUI" object.
}
});
doSomeWork.start();
});
}
}
Handler attached to UI thread.
Correct.
How android can run runnable in the same UI thread without new thread creation?
Any thread, including the main application ("UI") thread, can call post() on Handler (or on any View, for that matter).
Related
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
I want to implement some operations on UI thread after a delay of a few seconds and have tried this approach -
final Handler handler1 = new Handler();
final Runnable r = new Runnable() {
public void run() {
// operations to do
}
};
runOnUiThread(new Runnable() {
#Override
public void run() {
handler1.postDelayed(r, 1000);
}
});
Here I have two runnable objects, so my question is that are the operations I'm performing here being executed in UI thread or another thread because I don't directly execute the operations in Runnable object of the UI thread. Also if this is not the right approach to execute operations in UI thread after a delay, please suggest any modifications required.
When you post a Runnable with a Handler, the Handler executes it on whatever Thread created that Handler.
Handler's default constructor new Handler() is a synonym of new Handler(Looper.myLooper()). That might mean that the Handler will execute Runnables on the main thread, but only if the instantiation happened on the main Thread.
Either way, what you're doing is redundant. The runOnUiThread() is useless. Just change the Handler's constructor:
final Handler handler1 = new Handler(Looper.getMainLooper());
handler1.postDelayed(r, 1000);
I was trying to understand the looper and handler in android, but got stuck with the example written.
What I am trying to do is, add a looper to the thread, to make thread running continuously in run() method. Then post messages or runnables to the hanlder thread.
public class HLClass extends Thread {
Handler mHandler;
#Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HLClass","In Handler, Msg = "+msg.arg1);
}
};
Looper.loop();
}
}
This is how I am trying to call handler:
HLClass hlc = new HLClass();
hlc.start();
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
Error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Message android.os.Handler.obtainMessage()' on a null object reference
Here, what really I am trying to understand that, how I can attach a handler to thread and then post message from any other thread
How can I safely post Message or Runnable to handler without error.
You can try following code for sending message.
final HLClass hlc = new HLClass();
hlc.start();
new Handler().postDelayed(new Runnable() {
public void run() {
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
}
}, 300);
A Handler is a component that can be attached to a thread and then made to perform some action on that thread via simple messages or Runnable tasks. It works in conjunction with another component, Looper, which is in charge of message processing in a particular thread.
When a Handler is created, it can get a Looper object in the constructor, which indicates which thread the handler is attached to. If you want to use a handler attached to the main thread, you need to use the looper associated with the main thread by calling Looper.getMainLooper().
In this case, to update the UI from a background thread, you can create a handler attached to the UI thread, and then post an action as a Runnable:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// update the ui from here
}
});
This approach is a lot better than the first one, but there is an even simpler way to do this…
I use a Handler in my Service class to do some background work, but when it's done, I must execute some code on the Service's thread. Here's my code:
I create a handler in the Service's onCreate method.
HandlerThread handlerThread = new HandlerThread(getPackageName());
handlerThread.start();
Looper looper = handlerThread.getLooper();
mHandler = new Handler(looper);
How I use the Handler. This method is getting called dozens of times during a session.
mHandler.post(new Runnable() {
#Override
public void run() {
// It takes a few seconds to execute this method,
// so it must be running on a separate thread.
Object o = superMethod();
// However, this MUST be called from the Service's thread.
useObject(o);
}
};)
So how can I get back to the Service's thread?
Service itself runs on main thread here you want switch from Handler Thread(Background thread) to service(main Thread).
Handler handler = new Handler(getMainLooper());
handler .post(new Runnable() {
#Override
public void run() {
// do your main thread task here
}
});
I'm wondering when should I use handler.post(runnable); and when should I use
new Thread(runnable).start();
It is mentioned in developers documentation for Handler:
Causes the Runnable r to be added to the message queue. The runnable
will be run on the thread to which this handler is attached.
Does this mean if I write in the onCreate() of Activity class:
Handler handler = new Handler();
handler.post(runnable);
then runnable will be called in a separate thread or in the Activity's thread?
You should use Handler.post() whenever you want to do operations on the UI thread.
So let's say you want to change a TextView's text in the callback. Because the callback is not running on the UI thread, you should use Handler.post().
In Android, as in many other UI frameworks, UI elements (widgets) can be only modified from UI thread.
Also note that the terms "UI thread" and "main thread" are often used interchangeably.
Edit: an example of the long-running task:
mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// You may want to update a progress
// bar every second, so use a handler:
mHandler.post(new Runnable() {
#Override
public void run () {
// make operation on the UI - for example
// on a progress bar.
}
});
}
}).start();
Of course, if the task you want to perform is really long and there is a risk that user might switch to some another app in the meantime, you should consider using a Service.
To answer you specific question:
Does this mean if in the onCreate of Activity class I write:
Handler handler = new Handler() hanlder.post(runnable); then, runnable
will be called in a separate thread or on the Activity's thread?
No it won't be. The Runnable will be called on the Main Thread itself.
Handler is simply used for posting a message to the thread to which it is attached (where its is created).
It does not create a thread on its own.
In your example, you created a Handler in the main Thread (that where Activity.OnCreate() is called) and hence any message posted on such a Handler will be run on the Main Thread only.
Example is jacked:
mHandler = new Handler();
new Thread(new Runnable(){
#Override
public void run () {
mHandler.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
Alternatively you can skip the handler and use the post method on the view directly:
new Thread(new Runnable(){
#Override
public void run () {
mUiView.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
This is a good post that outlines the difference: What exactly does the post method do?
use handler.post() when you want to post the code (usually from background thread) to the main thread. Yea, POST,just like you, post a letter to someone. With the help of handler the code will be executed ASAP i.e. almost immediately.