I know a handler is bound to the thread's message queue in which it is created, but what if i create a handler in a service and posting a runnable declared in activity to which my service is bound.
For example:
In service:-
Handler handler=new Handler();
handler.post(Mainactivity.runnable);
In activity inside oncreate method:-
Runnable runnable=new Runnable(){
public void run{
//some code here
}
};
Can someone please explain me what's happening here?
Please find information about Message Queue and Looper in below link
Understanding Android Core: Looper, Handler, and HandlerThread
In the Android via Looper, Handler, and HandlerThread. The System can be visualized to be a vehicle as in the article’s cover.
1.MessageQueue is a queue that has tasks called messages which should be processed.
2.Handler enqueues task in the MessageQueue using Looper and also executes them when the task comes out of the MessageQueue.
3.Looper is a worker that keeps a thread alive, loops through MessageQueue and sends messages to the corresponding handler to process.
4 Finally Thread gets terminated by calling Looper’s quit() method.
By default service will run on UI Thread. So the handler you create on service will post the runnable on UI Thread
Related
As google says:
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue. Each Handler instance is
associated with a single thread and that thread's message queue. When
you create a new Handler, it is bound to the thread / message queue of
the thread that is creating it -- from that point on, it will deliver
messages and runnables to that message queue and execute them as they
come out of the message queue.
And i expect when i create a Handler in main thread (UI thread) it attached to this thread so it cause to freeze ui till end it's task. But in test this not happen and it is acts like it is on a backgound thread and do his task parallel.
I used to create Handle like this:
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i < 35000; i++) {
log.i(TAG,"log in Handler:"+i);
}}
};
mainHandler.post(runnable);
log.i(TAG,"log outSide");
In mainActivity (so handle should bound to Main thread). So what is the problem with this or am i create the handler in wrong way?
Some friends notice that doSomthing() is not complicated enough but why we see "log outSide" before "log in Handler:" if they are in a same thread.
Actually, It's working as you expected, Your handler is currently associated with your main thread because it is created in it and your task is also running on the same. Try to add Thread.sleep(1000) method inside your for loop then you will see the freeze in your UI.
Your current code runs with a complexity of O(1) since your N is constant, and your phone is capable enough to run this in a fraction of a second that's why you are not observing any freeze in your UI during the test.
Some friends notice that doSomthing() is not complicated enough but why we see "log outSide" before "log in Handler:" if they are in a same thread.
This is because of the delay in posting the Runnable to the Handler. Even though the Handler is created with the main thread's looper, there is still a small amount of delay between when post is called and when that Handler message is put into the Handler's queue and executed on the thread.
"log outside" runs instantaneously, so you see that log before the log within the Handler.
HandlerThread thread = new HandlerThread("DownloadService");
thread.start();
Is the looper associated with the thread waiting for a message to arrive in the message queue just after thread.start() returns? If so, then all I need to do is to associate the looper of this thread with a class that implements handleMessage(). Would this be the correct implementation?
Is the looper associated with the thread waiting for a message to arrive in the message queue just after thread.start() returns?
Not necessarily. start() only creates a thread that will --at some point in the future-- create a Looper. start() itself does not wait for the looper to be ready.
Edit: However, this usually is not a problem, since HandlerThread.getLooper() will wait for the looper to be properly prepared if it is not yet ready.
Side note: I think HandlerThread is not a well named class, since it actually only creates a Looper.
I have a Handler, mHandler, tied to the main thread. mHandler resides in a Service. Say I now post a Runnable to mHandler from the main thread like so:
public class SomeService extends Service {
// Handler is created on the main thread
// (and hence it is tied to the main thread)
private Handler mHandler = new Handler();
#Override
public void onDestroy() {
// onDestroy runs on the main thread
// Is the code in this Runnable processed right away?
mHandler.post(new Runnable() {
// (Some code statements that are to be run on the main thread)
...
});
super.onDestroy();
}
}
I know the example is a little silly as the Handler is unnecessary. However, it is a good example for this question.
Now my questions are:
Will the code statements in the Runnable be processed right away as the thread that posts the Runnable is also the thread that is to process the Runnable? Or does it work differently as the Handler internally uses a MessageQueue and hence there might be Runnables posted to the Handler elsewhere (which arrive before my Runnable)?
Moreover, is it possible that the statements will never run as the post(Runnable r) is an async call and hence onDestroy() will finish and the Service will be killed by the system before the Handler gets to run the code.
Thank you in advance.
Since a Service does not imply a separate thread, your runnable will be posted at the end of the main Looper's queue, so yes, there may be messages/runnables scheduled before yours.
Again, since Service does not imply a distinct thread, a call to onDestroy does not mean that the Handler's thread has been terminated. In this example, you are posting to the main looper, and that thread is active until the application process terminates.
since several days, I tried to figure out what exactly happens if I execute code in
void function(){
//somePreExecutionCode
new Handler().post(new Runnable(){
#Override
public void run(){
//someCode
}
});
}
It seems like it isn't blocking the UI, so buttons, which calls function() doesn't stuck in the clicked position until someCode has finished.
But if somePreExecutionCode starts a progressBar, the progressBar is shown at exactly the same moment, when someCode has finished.
I know, there are AsyncTasks for, but is there any other possibility?
And whats the difference between
new Handler().post
and
View.post
?
When an Android application is created, system creates a main thread of execution. This thread is referred to as UI thread and all UI related operations happen on this thread in order to avoid synchronization issues.
A Looper instance is created on this thread, which has a MessageQueue data structure. The Looper will be in an infinite loop waiting to read the Message / Runnable instances posted on the MessageQueue. To add Message7 / Runnable to the MessageQueue, Handler is used.
When you create a Handler instance, it will be associated with the current thread of execution and the Looper instance created on that particular thread.
Hence when you post a message via a Handler, the Message is added to the MessageQueue, which will be read in FIFO order by Looper and will be delivered to the target.
new Handler().post() and View.post are bit different.
When you post Messages via View.post, you are guaranteed the Message will be posted on UI thread's MessageQueue, since it internally uses Handler instance created on UI Thread.
If you create Handler instance on UI thread and post the Message using it on any thread, Message will be posted to the UI thread's MessageQueue.
If you create Handler instance on a non-UI thread and post Messages using it, they will be posted on non-UI thread's MessageQueue.
Putting it simply, there are Looper threads, for example, UI thread. Such thread has its own Looper, which runs a message loop for the thread.
Such thread, typically, has a Handler, which processes its Looper's messages - overriding public void handleMessage(Message msg) or executing a Runnable, which was posted to it's looper's message queue.
When you're creating a Handler in the context of UI thread (like you did in your code), it gets associated with UI thread's looper, so your \\someCode runs on UI thread.
I guess, in your use case new Handler().post(Runnable) and View:post(Runnable) are mostly the same, as they both add a Runnable to the UI thread message queue.
But they are not the same.
View:post(Runnable) will add a Runnable to the UI thread looper's message queue;
Handler:post(Runnable) will add a Runnable to its associated thread looper's message queue
My explanation is pretty much intuitive, so correct me anyone if I am wrong.
According to the Android View's documentation:
The Runnable will be run on the user interface thread
According to the Android Handler's documentation:
The Runnable will be run on the thread to which this handler is attached
So, in the Handler's case, you can create it in any thread you want, it's a kind of anchor that will execute the Runnable you provide in the thread it was created in.
In the View.post, you will always execute the Runnable in the uI thread.
I have a simple question: is it possible to restart (re- loop()) thread's Looper if it was previously quit. For instance, i have design my thread as follow:
public class ProvaThread extends Thread implements Runnable{
public void run(){
Looper.prepare();
Handler handler = new Handler(){
Log.d(TAG, "handle message..");
#Override
public void handleMessage(Message msg){
getLooper().quit();
}
};
Looper.loop(); //loop 1
Log.d(TAG, "thread continue (1)...");
Looper.loop(); //loop 2
Log.d(TAG, "thread continue (2)...");
}
}
I have tried this code but i get a RuntimeException (sending message to a Handler on a dead thread) when i try to post a message to the handler the second time (handleMessage() is not called after second loop()). I came to conclusion that when getLooper().quit() is called is it possible to recall loop() but is it not possible to handle new messages, otherwise exception is thrown). Is it correct?
Should i use wait()/notify() to make this??
Let me first explain why your example code doesn't work. A Looper only handles one, and only one, MessageQueue. This MessageQueue is created when you call Looper.prepare() and the messages are processed when you call Looper.loop(). Once you have called Looper.quit() two things happen:
The MessageQueue to the Looper is put in a final terminal state where it will not process any incoming messages; a RuntimeException is thrown.
It will only return "null" as message when the Looper tries to retrieve messages.
So, (1) is the reason for your RuntimeException and (2) allows you to try and and restart the message retrieval with Looper.loop() but only "null"-objects are returned from the MessageQueue.
Secondly, let me suggest a better approach to solve a continuous communication between the UI and a worker thread:
Create a Handler for the UI thread, called mUiHandler.
Create a worker thread, e.g. HandlerThread, and expose a Handler, called mWorkerHandler.
Now, let the two handlers communicate by sending messages back and forth. Post messages to the mWorkerHandler for background tasks and let the worker thread post messages to the mUiHandler whenever a dialog shall be shown or removed.
I think you should read this short article http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/. It explains how Looper works and how to use it.