Recently I have checked a lot of handler knowledge on the Internet, but I always feel that there are many problems ??
1. Why handler? (Answer: 1) send a message as planned or execute a runnanble (using the POST method), similar to a timer;
2) put messages sent from other threads into the message queue to avoid thread conflicts (often used in updating UI threads );)
2. handler is asynchronous. is creating a handler instance a new thread ?? (No, no new thread was created, but why didn't the main thread be blocked?This is a systematic Logoff)
3. In the same thread, handler1 sends a message. Can handler1 receive the message, and handler2 receive the message? (It can only be received in handler1)
4. Can handler and sendmessage defined in the main thread be used in the child thread to receive the handler in the main thread? (Yes)
5. Create a handler instance in the sub-thread and send a message. Is this all right ??? (Exception occurred)
6. What is handlerthread and when to use it ?? (You do not want to create a logoff because handlerthread has logoff and message queue by default)
7. What is the relationship between message, logoff, handler, messagequeue, and other places ???
8. What is the difference between sendmessage and post ?? Do you want to share a Message Queue messagequeue ?? (They use the same handlerthread;
The difference between sendmessage and post is that there is a difference between dispatchmessage () in the loop () function of logoff.
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } }
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
Call the method starting with post in the handler class to wrap a runnable object in a message object, and then press it into the message queue,The callback field of the message to be queued is not null.,The value is the runnable object.. Call these methods of the handler object to queue the message, and its target attribute will be assigned to this handler object.
Message parameters are also set.
)
9. Is handler in the main thread? (Not necessarily, it is normal, but if the Logoff of the sub-thread is passed in the handler constructor, it will be in the thread)
10. The Handler constructed in the Child thread can pass in the Logoff of the main thread, that is, control the message queue of the main thread ?? (Yes)
I think it should be interesting to learn handler with questions. The following is how to solve these problems, (* ^__ ^ *) Xi ......
First, introduce the basic knowledge of handler.
Handler
Handler is responsible for sending and processing messages in Android. ItsMain Purpose:
1) send a message as planned or execute a runnanble (using the POST method ),Similar to Timer;
2) put messages sent from other threads into the message queue to avoid thread conflicts (often used in updating UI threads );
By default, Handler accepts the message loop instances in the current thread (using handler (locycling) and handler (locycling logoff, handler. Callback callback) to specify the thread ),At the same time, a message queue can be distributed and processed by multiple objects in the current thread.(In the UI thread, the system already has an activity to process, and you can start several handler to process it ). When handler is instantiated, logoff can be any thread. As long as there is a handler pointer, any thread can also sendmessage. Handler does not process messages concurrently. One Logoff
The next message is read only after processing a message. Therefore, the processing of the message is in the form of a blocking (handlemessage () method, and time-consuming operations can be placed in other threads for execution, after the operation, send a message (via the sendmessges method), and then update the UI by handlemessage ).
Logoff
Logoff classCreates a message queue. Each thread can have at most one message queue.In Android, UI threads have message queues by default, but non-UI threads do not have message queues by default. if you want to enable message queue in a non-UI thread, you need to call logoff. prepare () method, a logoff object is created during the execution of this method, and a messagequeue instance is created in the logoff Constructor (The logoff constructor is private, an object cannot be created outside the logoff class ). then bind a handler to the thread.
Instance, and then call logoff. the loop () method can continuously retrieve and process messages from the message queue. logoff. the myloop () method can obtain the logoff object of the thread. If it is null, the thread has not enabled Message Queue yet.
Create a messagequeue object (A logoff corresponds to a messagequeue ). Besides the default logoff for the main thread, other threads do not have messagequeue objects by default. Therefore, messages cannot be accepted. If you need to accept it, define a looper object (through the prepare function) by yourself, so that the thread has its own Looper object and messagequeue data structure.
Logoff extracts the message from messagequeue and submits it to handlemessage of handler for processing. After the processing is complete, call message. Recycle () to put it into the message pool.
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
Message
Message: the message object, which is stored in the message queue. A Message Queue contains multiple messages. Message Instance Object acquisition,Usually use the static method obtain () in the message class (),This method has multiple overloaded versions to choose from;It does not necessarily create a new instance directly., But first from the message pool (Message pool) to see if there is any available message instance, then directly retrieve and return this instance. If the message pool
The specified parameter is used to create a message object. When removemessages () is called, the message is deleted from the message queue and put into the message pool. In addition to the above method,You can also obtain a message instance through the obtainmessage () of the handler object..
The message class is used to indicate that the message object can carry data through the arg1, arg2, OBJ fields and setdata () fields. In addition, there are many fields.
The when field determines when the message should be processed ,;
The target field is used to indicate which handler object processes the message.;
The next field indicates the next message after the message in the message queue;
CallbackIf it is not null, this message encapsulates a runnable object.;
What field indicates code,That is, the type of the message.Everything is in the namespace of the handler. We only need to ensure that the attributes of the messages processed by the same Handler are not repeated.
Messagequeue
The messagequeue class is used to represent a message queue. each message in the queue has a when field, which is used to determine when the message should be processed. each message in a message queue is arranged in ascending order based on the size of the when field. The message at the top is processed first. Therefore, the message queue is not a strict FIFO queue. When the main thread is created, a default logoff object is created, and a message queue is automatically created when the logoff object is created. Other non-main threads do not automatically create logoff. When necessary, call prepare
Function.
Push a message to a message queue:
The target field of the message object is associated with the message queue of the thread to which the message is pushed.
A calls the method starting with send in the handler class to push the message object into the message queue ,;
Call the method starting with post in the handler class to wrap a runnable object in a message object and then press it into the message queue. In this case, the callback field of the message to be queued is not null, the value is the runnable object. the target attribute of the message that calls the methods of the handler object to queue is assigned to this handler object.
B. Call the sendtotarget () method of the message object to push itself into the Message Queue associated with its target field (that is, the handler object.
Retrieve a message from the message queue and process the message:
All messages in the message queue have the target field. messages are retrieved and processed on the Thread associated with the target.
1. if the callback field of the retrieved message object is not null, call the run () method of the callback field (the callback field type is runnable ). note that a new thread is not enabled to run the run () method, but directly runs on the Thread associated with the handler object (that is, the target field of the message.
2. if the callback field of the retrieved message object is null and the callback field in the handler object is null, the message will be processed by the handlemessage (MSG) method of the handler object. note that the callback field of the message object is of the runnable type, while the callback field of the handler object is of the callback type. The callback field of the handler object is specified when the handler instance is created, if not specified, this field is null. For details, see the four constructor methods of the handler class.
3. If the callback field of the retrieved message object is null and the callback field in the handler object is not null, the message will be processed by the handlemessage method of the callback field in the handler object.
Inter-thread Communication
With the above descriptions, the communication between threads is easy to understand. if a handler is associated with a message queue on thread a, we can call the handler Method on thread B to push a message to the message queue on thread, this message will be processed on thread.
Code:
Public class handlerdemo extends activity {private final static int message_id = 5; private testhandler1 mtesthandler1; private testhandler2 mtesthandler2;/** called when the activity is first created. * // @ overridepublic void oncreate (bundle savedinstancestate) {super. oncreate (savedinstancestate); setcontentview (R. layout. main); mtesthandler1 = new testhandler1 (); mtesthandler2 = new testhandler2 (); button BTN = (button) findviewbyid (R. id. clcik); BTN. setonclicklistener (new view. onclicklistener () {@ overridepublic void onclick (view v) {// todo auto-generated method stubnew thread (New runnable () {// Note 1 @ overridepublic void run () {// todo auto-generated method stub // send a message // get the message object directly from handler. Of course, you can also get a new one, but we recommend the previous message MSG = mtesthandler1.obtainmessage (); // Note 2 bundle B = new bundle (); B. putstring ("color", "Red"); // put the data sent to handler in the message MSG. setdata (B); MSG. what = message_id; mtesthandler1.sendmessage (MSG); // Note 1 }}). start () ;}});} private class testhandler1 extends handler // Note 1 {@ overridepublic void handlemessage (Message MSG) {// todo auto-generated method stubsuper. handlemessage (MSG); If (MSG. what = message_id) {// Note 3 bundle B = MSG. getdata (); string colorstr = B. getstring ("color"); log. D ("handlerdemo", "testhandler1 ---------" + colorstr); // mainthread 1 // log. E ("myhandler Handler -->", thread. currentthread (). GETID () // + ""); // log. E ("myhandler Handler -->", thread. currentthread (). getname () // + "") ;}} private class testhandler2 extends handler // Note 1 {@ overridepublic void handlemessage (Message MSG) {// todo auto-generated method stubsuper. handlemessage (MSG); If (MSG. what = message_id) {// Note 3 bundle B = MSG. getdata (); string colorstr = B. getstring ("color"); log. D ("handlerdemo", "testhandler2 ---------" + colorstr); // mainthread 1 // log. E ("myhandler Handler -->", thread. currentthread (). GETID () // + ""); // log. E ("myhandler Handler -->", thread. currentthread (). getname () // + "");}}}}
Note 1:
Inherit from two sub-classes of handler, testhandler1 and testhandler2, and create two objects respectively in the main thread;
Create a subthread and send messages using the mtesthandler1 object defined in the main thread.
Message MSG = mtesthandler1.obtainmessage (); // Note 2 bundle B = new bundle (); B. putstring ("color", "Red"); // put the data sent to handler in the message MSG. setdata (B); MSG. what = message_id; mtesthandler1.sendmessage (MSG); // Note 1
NOTE 2 ::
It is best to use
Message msg = mTestHandler1.obtainMessage();
Method to obtain the message object. Of course, you can create a new message object;
Setdata: inserts data into the message object for transmission;
What parameter is used to differentiate messages sent to the same handler;
Result:
In this way, we can solve the two problems mentioned above;
Handler isThe handler that sends the message must receive it from;Mtesthandler1 sends, testhandler1 receives, testhandler2 does not receive;
The subthread can send a message to the handler object defined in the main thread;
What if handler is defined in a child thread ???
Replace mtesthandler1.sendmessage (MSG); with the following code:
New handler () // Note 4 {@ overridepublic void handlemessage (Message MSG) {// todo auto-generated method stubsuper. handlemessage (MSG); If (MSG. what = message_id) {bundle B = MSG. getdata (); string colorstr = B. getstring ("color"); log. D ("handlerdemo", "internal class ---------" + colorstr );}}}. sendmessage (MSG );
In this way, the program attendance is abnormal because logoff is not called. prepare (), no logoff instance, so ..... however, this also indicates that a common sub-thread has no logoff instance and no message loop;
For this problem, handlerthread can be used to avoid exceptions, because handlerthread has logoff instances ....
// (3)new HandlerThread TestHandlerThread testHandlerThread = new TestHandlerThread("testHandlerThread");testHandlerThread.start();
Private class testhandlerthread extends handlerthread {// Note 5 Public testhandlerthread (string name) {super (name); // todo auto-generated constructor stub} @ overridepublic void run () {// todo auto-generated method stubsuper. run (); message MSG = mtesthandler1.obtainmessage (); bundle B = new bundle (); B. putstring ("color", "Red"); // put the data sent to handler in the message MSG. setdata (B); MSG. what = message_id; logoff = This. getlooper (); new handler (loler) {@ overridepublic void handlemessage (Message MSG) {// todo auto-generated method stubsuper. handlemessage (MSG); log. D ("handlerdemo", "testhandlerthread ---------");}}. sendmessage (MSG );}}
In this way, problem 5.6 is solved;
Implement handler in the Child thread, generate a handler object, and create a Message Queue (that is, a logoff object, through prepare (), loop () in the Child thread ()) (or get the message queue in the main thread,Control the message queue of the main threadLooper. getmainlooper (), which is acceptable, but has no practical significance...
Note:
By default, the subthread does not have a message queue .......
The handler sends and receives the same object, whether in the same thread or not...
The post and sendmessage of handler process the same message queue (this can be seen from the source code .....)
In dispatch, post is processed by judging the callback, and handlecallback (MSG) is called; whileSendmessage is handled by calling handmessage;
Leave a message if you have any questions...