Understanding Looper
Looper is used to add a message queue (MessageQueue) to a thread, and to loop through a tool that, when there is a message, evokes a thread to process the message until the thread is finished. Looper is not normally used because, for system components such as Activity,service, frameworks has initialized a thread (commonly known as a UI thread or main thread) with a looper in it and a message queue created by Looper. So the main thread runs all the time and handles user events until some event (back) exits.
If we need to create a new thread, and the thread has to be able to iterate over the message events from other threads, or if we need to have a long, complex interaction with other threads, we need to use Looper to establish a message queue for the thread.
The use of Looper is also very simple, its method is less, the main four:
Public static prepare ();
public static mylooper ();
public static loop ();
public void Quit ();
use the following methods:
1. Call Looper.prepare () at the very beginning of each thread's run () method, which is the initialization of Message Queuing for the thread.
2. Then call Looper.mylooper () to get a reference to this Looper object. This is not necessary, but if you need to save the Looper object, be sure to prepare (), otherwise the method called on this object does not necessarily have an effect, such as looper.quit () will not exit.
3. Add handler to process messages in the run () method
4. Add the Looper.loop () call, which allows the thread's message queue to start running and receive the message.
5. When you want to exit the message loop, call Looper.quit () Note that this method is to be called on the object, it is obvious that the object means to exit the specific looper. If there are no other actions in run (), the thread will terminate.
Let's look at an example
instance
This example implements a service that performs a task:
Copy Code code as follows:
public class Looperdemoactivity extends activity {
Private Workerthread Mworkerthread;
Private TextView Mstatusline;
Private Handler Mmainhandler;
@Override
public void OnCreate (Bundle icicle) {
Super.oncreate (Icicle);
Setcontentview (r.layout.looper_demo_activity);
Mmainhandler = new Handler () {
@Override
public void Handlemessage (msg) {
String text = (string) msg.obj;
if (Textutils.isempty (text)) {
Return
}
Mstatusline.settext (text);
}
};
Mworkerthread = new Workerthread ();
Final Button action = (Button) Findviewbyid (r.id.looper_demo_action);
Action.setonclicklistener (New View.onclicklistener () {
public void OnClick (View v) {
Mworkerthread.executetask ("Please do me a favor");
}
});
Final Button end = (Button) Findviewbyid (r.id.looper_demo_quit);
End.setonclicklistener (New View.onclicklistener () {
public void OnClick (View v) {
Mworkerthread.exit ();
}
});
Mstatusline = (TextView) Findviewbyid (R.id.looper_demo_displayer);
Mstatusline.settext ("Press ' do me a favor ' to execute a task, press ' end of service ' to stop Looper thread");
}
@Override
public void OnDestroy () {
Super.ondestroy ();
Mworkerthread.exit ();
Mworkerthread = null;
}
Private class Workerthread extends Thread {
Protected static final String TAG = "Workerthread";
Private Handler Mhandler;
Private Looper Mlooper;
Public Workerthread () {
Start ();
}
public void Run () {
Attention:if you obtain looper before Looper#prepare (), can still use the Looper
To process message even after your call Looper#quit (), which means the looper does
Really quit.
Looper.prepare ();
So we should call Looper#mylooper () after Looper#prepare (). Anyway, we should put all stuff between looper#prepare ()
and Looper#loop ().
In the case, you'll receive "handler{4051e4a0} sending message to a Handler on a dead thread
05-09 08:37:52.118:w/messagequeue (436): java.lang.runtimeexception:handler{4051e4a0} Sending message
To a Handler on a dead thread, while try to send a message to a looper which looper#quit () had called,
Because the thread attaching the Looper and Handler dies once () Looper#quit gets.
Mlooper = Looper.mylooper ();
Either new Handler () and new Handler (Mlooper) 'll work
Mhandler = new Handler (mlooper) {
@Override
public void Handlemessage (msg) {
/*
* Attention:object message isn't reusable, you are must obtain a new one for all time and you are want to use it.
* Otherwise you got "Android.util.AndroidRuntimeException: {what=1000 when=-15ms obj=it are I please
* To serve for your, please be patient to wait!........} This am already in use. "
*/
Message newmsg = Message.obtain ();
StringBuilder sb = new StringBuilder ();
Sb.append ("It is me please to serve for you, please be patient to wait!\n");
LOG.E (TAG, "workerthread, it is me please to serve for you, please be patient to wait!");
for (int i = 1; i < i++) {
Sb.append (".");
Message newmsg = Message.obtain ();
Newmsg.obj = Sb.tostring ();
Mmainhandler.sendmessage (NEWMSG);
LOG.E (TAG, "workthread, working" + sb.tostring ());
Systemclock.sleep (100);
}
LOG.E (TAG, "workerthread, your work are done.");
Sb.append ("\nyour work is done");
Message newmsg = Message.obtain ();
Newmsg.obj = Sb.tostring ();
Mmainhandler.sendmessage (NEWMSG);
}
};
Looper.loop ();
}
public void exit () {
if (mlooper!= null) {
Mlooper.quit ();
Mlooper = null;
}
}
This is returns immediately, it just push an to Thread ' s MessageQueue.
can also call this method continuously, the task would be executed one by one
Order of which they are pushed into MessageQueue (they are).
public void ExecuteTask (String text) {
if (Mlooper = null | | mhandler = NULL) {
Message msg = Message.obtain ();
Msg.obj = "Sorry man, it's out of service";
Mmainhandler.sendmessage (msg);
Return
}
Message msg = Message.obtain ();
Msg.obj = text;
Mhandler.sendmessage (msg);
}
}
}
In this instance, the main thread executes the task only by Cheng a message to the service line and passing the relevant data over, the data is packaged into a message object, then placed in the message queue of the service thread, and the main thread's call returns, which is fast, so it does not block the main thread. The service thread wakes up messages from the queue whenever a message enters the message queue, and then executes the task. Service threads can receive as many tasks as the main thread can keep sending messages to service threads, which are put into message queues, and the service threads execute them one after the other----until all tasks are completed (message queues are empty, no more messages are available), The service thread will go into hibernation again----until a new message arrives.
If you want to terminate the service thread, calling quit () on the Mlooper object exits the message loop because the thread has no other action, so the entire thread terminates.
It should be noted that when a thread's message loop has exited, no more messages can be sent to it, otherwise there will be an exception thrown "runtimeexception:handler{4051e4a0} sending messages to a Handler on a dead Thread ". Therefore, it is recommended that after Looper.prepare (), call Looper.mylooper () to obtain a reference to this looper, which is used to terminate (quit () must be called on the object), and to check that the message loop has exited when the message is received (as in the previous example )。