Use Handler in Android to implement message distribution mechanism (zero)
In the previous article about AsyncTask, we finally mentioned that AsyncTask uses the asynchronous Message processing mechanism of Handler to return operation results and messages to the main thread, to update the UI thread.
In our daily development work, Handler is also one of the classes we often use. What is the main role of Handler?
Handler is mainly used for asynchronous processing of messages (messages can be some UI updates we want to do, or some other invisible operations, such as database operations, I believe everyone understands the concept of Asynchronization.
To put it simply:
1) from the program perspective, when a line of code is executed, an asynchronous request (Message) is sent, and the program does not need to wait on this line of code, but the code that can continue to be executed.
2) from the user's point of view, the user sends a message and can do other things without doing anything or doing nothing, after the corresponding message is processed, the corresponding result is processed through the callback mechanism.
Therefore, the asynchronous message processing mechanism of Handler in Android can provide users with a more reasonable and friendly user experience. Of course, Android is implemented by Handler, and other platform environments also have their own asynchronous implementation mechanism. The principle is the same and the name is different.
Since we are developing Android, we must learn how to use Handler and explore the code architecture hidden behind Handler.
First, let's get started with a simple example and learn how to use Handler.
The Code is as follows:
public class MainActivity extends ActionBarActivity { private static final int MSG_ID_1 = 1; private static final int MSG_ID_2 = 2; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: break; } } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Message message = mHandler.obtainMessage(); message.what = MSG_ID_1; mHandler.sendMessage(message); }}
When we start the program, we can see that the following information has been printed in LogCat:
10-27 15:13:21.382: V/Test(9618): Toast called from Handler.sendMessage()
In handleMessage of handler, msg. what = MSG_ID_1 is processed.
From this simple example, we can sum up the Handler usage steps, which include the following steps:
1) create a Handler object and implement its handleMessage (Message msg) method, as shown in the Code:
private Handler mHandler = new Handler() {
The handleMessage method is implemented step by step. We can see that a Message object is obtained.
The Message object encapsulates some parameters, which are commonly used as follows:
A) what parameter: This is an int value, which is often used to differentiate a Message ID. In this example, we assign MSG_ID_1 to msg. what when creating a message.
B) obj parameter: This is an Object. With the obj parameter, any object can be assigned to the message and then processed in handleMessage, which is also the method for Handler to transmit data in asynchronous processing.
C) parameters such as arg1 and arg2: a) and B) are the parameters of the most common Message. Basically, these two parameters are enough, however, the Message still provides other fields for our use, such as argX, which is short for arguments.
2) After creating the Handler object, you need to create a Message object in step 2. There are two ways to create a Message object:
2.1) directly create a new object. The Code is as follows:
Message msg = new Message()
2.2) use the Handler. obtainMessage () method, that is, the method used in the code above, as follows:
Message message = mHandler.obtainMessage();
Generally, we recommend the second method. Why?
Because an object similar to the Message pool is maintained in the Message, when Handler is used to distribute messages, the Message object is not necessarily destroyed immediately after processing, instead, it may be stored in a message pool.
When Handler's obtainMessage method is used, Handler will retrieve an existing object from the message pool and initialize its information. In this way, we do not need to re-create an object, some memory is wasted. In embedded applications, the memory is not very large, which is an optimization of performance.
When creating a Message, we can assign values to msg. what to determine the purpose or purpose of the Message during handleMessage.
Of course, there must be different processing methods for different needs. This is a detailed analysis of the specific situation.
3) after the Message is created, we can use the sendMessage of Handler to send the Message. Then, the Message will be captured by handler, and then proceed.
Next, let's expand the example. The Code is as follows:
public class MainActivity extends ActionBarActivity { private static final int MSG_ID_1 = 1; private static final int MSG_ID_2 = 2; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Message message = mHandler.obtainMessage(); message.what = MSG_ID_1; mHandler.sendMessage(message); Message msg2 = mHandler.obtainMessage(); msg2.obj = "I'm String from Message 2"; msg2.what = MSG_ID_2; mHandler.sendMessage(msg2); }}
The result is as follows:
10-27 15:35:19.168: V/Test(12135): Toast called from Handler.sendMessage()10-27 15:35:19.168: V/Test(12135): I'm String from Message 2
From this, we can see that using the obj parameter, we pass the String object to handleMessage.
In addition to the sendMessage method, Handler can also use the following method when sending a message:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } public final boolean sendMessageAtFrontOfQueue(Message msg) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, 0); }
As we can see, no matter whether it is sendEmptyMessage or sendMessage, The sendMessageAtTime method is called to put the corresponding Message object into a MessageQueue.
So why do they need to be placed in MessageQueue? In MessageQueue, how does one return to handleMessage of Handler?
Next, let's continue to learn.
This article briefly introduces how to use Handler, a simple example, and a simple entry.
End.