Do we need invoking Looper.prepare() when invoking Handler - android

I need to understand about the Looper. Looper will consult appropiate handler to to send and process Message and Runnable objects associated with a thread's MessageQueue.
By default, a thread does not have a message loop associated with it, hence doesn’t have a Looper either. To create a Looper for a thread and dedicate that thread to process messages serially from a message loop, you can use the Looper class.
The following is my code I don't invoke Looper explicitly
Thread background2 = new Thread(new Runnable() {
#Override
public void run() {
for ( int i = 0; i < 5; i++) {
final int v =i;
try { Thread.sleep(1000);
handler.post(new Runnable() {
#Override
public void run() {
txt.setText(txt.getText() + "Thread 2 current i : " + String.valueOf(v) +System.getProperty("line.separator"));
}
});
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
}
});
Does it mean that the task/runnable is not put in the queue? what's the difference of above code with this
Thread background3 = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
for ( int i = 0; i < 5; i++) {
final int v =i;
try { Thread.sleep(1000);
handler.post(new Runnable() {
#Override
public void run() {
txt.setText(txt.getText()+ "Thread 3 set : " + String.valueOf(v) +System.getProperty("line.separator"));
}
});
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
Looper.loop();
}
});
both of them accessing a same handler. They both work fine.

Creating a Looper for a Thread means you're setting up that Thread to receive messages from other Threads. Both of your examples are behaving exactly the same because the you're not sending anything to the Thread in the second example. That is, the background3's Looper isn't really being used.
In both examples, you're posting a Runnable to a Handler that was created for the main Thread's Looper. You're not creating that Handler for, e.g., background2. That Handler belongs to the main Thread and its Looper, and anything you post to it will be put into the main queue, and run on the main Thread.
The only difference in your examples is that the second Thread has a Looper, and you could post to it, if you wanted to. To do that, you would create another Handler that belonged to background3's Looper, and post to that. You're not doing that, though, so the second Thread just continues to run without doing anything else.
A Thread doesn't need a Looper simply to post to another Thread's Handler, which is really all that your examples are doing. That other Thread - the main Thread, in this case - has already prepared and started its Looper. You're just sending Runnables to it, and you don't need a Looper of your own to do that.

Related

When i post a long running Runnable to the main thread why isn't it blocked for that time?

If i post a Runnable with Thread.sleep(10000) command, why is the system behaving normally if the UI Thread can only execute one message at a time?
I made this thread in the main activity. Button clicks are processed by the main thread from the MessageQueue, then if the runnable in h.post() is currently active on the main thread then how are the button clicks being processed? shouldn't they wait in the MessageQueue?
new Thread(new Runnable() {
public void run() {
for(int ii=0;ii<9;ii++){
i++;
try
{
Thread.sleep(1000);
h.post(new Runnable(){
#Override
public void run()
{
t();
// TODO: Implement this method
}
});
}
catch (InterruptedException e)
{}
}
}
}).start();
final Runnable r = new Runnable() {
public void run() {
Thread.sleep(10000);
//the thread stoped/sleeped is the thread of Runnable belongs to,
//but not the Main UI thread
}
};
Not block Main UI thred is exactly what Runnable want to achieve.
Aw that was a very trivial question. The inner Runnable is on the main thread while the outer one is time consuming. So the inner Runnable won't block the UI Thread. Thanks!

Looper Handler Example

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…

Running a Method for a Certain Number of Time

So I have this method called PredictionEngine(int) that I want to run a certain number of time with a certain time-delay between each run. The method goes like this:
private void PredictionEngine(int delay) throws Exception {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
enableStrictMode();
String val = null;
try {
if (tHighPass == 0 && tLowPass == 0 && tKalman == 1) {
//Magic
} else {
//Magic
}
} catch (Exception e) {
e.printStackTrace();
}
enableStrictMode();
new DropboxTask(side_output, "Result", val).execute();
}
}, delay);
}
As obvious, I am running a network operation in the main thread as this is a research app and no client is ever going to use it.
I want this whole function to run for say a 100 times with a certain delay, say 2 seconds. The initial thought was to do this:
for(loop 100 times){
PredictionEngine(int)
Thread.sleep(2000); //sorry for StackOverflow programming.
}
However I don't want to block the main thread as I am reading some sensor data there. Any ideas for the same would be very helpful!
Thanks.
The best way to solve this is by using rxJava library, because it allow to create, modify and consume streams of events. You can implement everything in a few lines of code and modify it so operatioin will be performed in background as well.
Observable.interval(1, TimeUnit.SECONDS)
.take(100)
// switch execution into main thread
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(t -> {
doSomethingOnMainThread();
});
On the other hand, there is another solution- you can use Handler, which is usually bein used for thread communication. It has method .postDelayed() allowing you to postpone execution of task. Handler can be conveniently used along with HandlerThread. But, rxJava is more convenient and simple way to solve your problem.
While creating your Handler, you can provide a looper as one of the constructors parameters that is based on different thread then the main thread:
HandlerThread thread = new HandlerThread("Thread name", android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper looper = thread.getLooper();
Handler handler = new MyHandler(looper);
Messages received by MyHandler will be processed on a separated thread, leaving the UI thread clear from interferences.
To loop on the task periodically, use something like:
for (int i=0; i<100; i++){
handler.postDelayed(new Runnable(){
...
...
...
}, i*delay);
}
This way, in case you decide that the periodic tasks need to be canceled, you will always be able to invoke:
handler.removeCallbacksAndMessages(null);
I tried to solve the issue as follows without blocking the main Thread
I created the worker thread for looping and still running the predictionEngine() on main thread
MyThread t = new MyThread(2000, 3000); // delay and sleep
t.startExecution();
Worker thread class looks as follows
class MyThread extends Thread{
private int delay;
long sleep;
MyThread(int delay, long sleep){
this.delay = delay;
this.sleep = sleep;
}
#Override
public void run() {
for(int i = 0; i < 100; i++){
try {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
predictEngine(delay);
}
});
Log.i("Mtali","About to pause loop before next predict");
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void startExecution(){
start();
}
}
Hop this helps!

looper.prepare question

i am trying to loop a toast inside a timer but the toast doesn't show
the log in logcat shows that cannot create handler inside thread that has not called looper.prepare() i am not sure what it means
int initialDelay = 10000;
int period = 10000;
final Context context = getApplicationContext();
TimerTask task = new TimerTask()
{
public void run()
{
try
{
if (a != "")
{
Toast toast = Toast.makeText(context, "Alert Deleted!", Toast.LENGTH_SHORT);
toast.show();
}
}
catch (Exception e)
{
}
}
};
timer.scheduleAtFixedRate(task, initialDelay, period);
what my application does is that every 10 sec it would check if a certain variable is empty. if it is empty then it will show a toast.
i have no problem doing this in a service class but when i try to implement this into
public void onCreate(Bundle savedInstanceState)
i get this error
You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.
see this answer....
Can't create handler inside thread that has not called Looper.prepare()
You can show this toast in alternative ways also
class LooperThread extends Thread {
public Handler mHandler;
#Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Now as you see this handler is created in normal thread so if you try n send any message from it , it will throw an exception so by bounding it with Looper.prepare() and Looper.loop() you can make any statements executed within it on UI thread
Another Example
Looper allows tasks to be executed sequentially on a single thread. And handler defines those tasks that we need to executed. It is a typical scenario that I am trying to illustrate in example:
class SampleLooper {
#Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
} catch (Throwable t) {
Log.e(TAG, "halted due to an error", t);
}
}
}
Now we can use the handler in some other threads(say ui thread) to post the task on Looper to execute.
handler.post(new Runnable()
{
public void run() {`enter code here`
//This will be executed on thread using Looper.`enter code here`
}
});
On UI thread we have an implicit Looper that allow us to handle the messages on ui thread.

How does Android/DalvikVM process Handlers?

I'm wondering how Handlers are processed in Android/DalvikVM. I'm writing an application for Android, and in one class I have a Handler method which receives messages from another class. Will the Handler method act as a Thread and be asynchronous to the run() method in the same class, or will it wait until a line of code in the run() method is finished (sort of atomic operation)? Or something else?
I'm wondering, because I want to add messages to a queue in the Handler method, and process and remove them in the run() method (producer-consumer).
My code structure:
public class Parser implements Runnable {
public void run() {
while(true) {
// Remove a byte from the ring buffer and parse it
byte b = Ringbuffer_read();
// Parse
try {
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
// Store all the received bytes in the ring buffer
for (int i = 0; i < msg.arg1; i++) {
Ringbuffer_store(((byte[]) msg.obj)[i]);
}
break;
}
}
};
}
When will the code in the handler run? Does it interrupt the code in the run() method at any point? Do I have to have some synchronization or semaphores or something around the code in the run() and handler method so that I don't corrupt my buffer?
An Android Handler associates itself with whatever thread it is created in (assuming that thread has a looper already). By default in Android callbacks run on a thread named "main" which is also called the ui thread. Regardless of what thread the post method is called from the handleMessage method will be called from the thread that the Handler was created in (usually the "main" thread). Because the handleMessage method is always called in the same thread, only one message will be processed at a time.
If your plan is to have only a single consumer then Handler is a good choice. You will not need to remove messages from your consumer (the Handler), instead they will simply arrive in handleMessage for processing. If you want to do processing on the "main" thread then you just make a new Handler, if you want to do processing in the background to avoid ANRs you will likely want to use HandlerThread. Here's an example of a Handler running on it's own background thread:
HandlerThread handlerThread = new HandlerThread("Consumer");
handlerThread.start();
Handler consumer = new Handler(handlerThread.getLooper()) {
public void handleMessage (Message msg) {
}
};
Notice that in the description above class does not come into play at all because classes are how code is structured which is unrelated to what thread the code is executed on.

Categories

Resources