In Android, messages are often used for information interaction within threads or between threads, and if we are familiar with its internal principles, it will make it easier and better to structure the system and avoid some low-level errors. Before learning about the message mechanism in Android, let's take a look at several messages-related classes:
1.Message
A Message object, as its name implies, is a class that records message information. There are several more important fields for this class:
A.arg1 and Arg2: We can use two fields to store the integer value we need to pass, and in the service we can store the service ID.
B.obj: The field is type object, and we can have the field pass a number of items to the recipient of the message.
C.what: This field can be said to be the flag of the message, in the message processing, we can according to the different values of this field for different processing, similar to when we handle button events, through the switch (V.getid ()) to determine which button is clicked.
When using the message, we can create a message instance with the new message (), but Android recommends that we pass Message.obtain () or handler.obtainmessage () Gets the message object. This is not necessarily a direct creation of a new instance, but rather a message from the pool to see if there are any instances of messages available, and the existence is directly removed and returned to this instance. Conversely, if there is no message instance available in the messages pool, a new one is given based on the parameter. By analyzing the source, the Android system instantiates 10 message objects in the messaging pool by default.
2.MessageQueue
message queues, which store the data structure of a Message object, and store messages according to the "FIFO" principle. Instead of storing in real sense, the message object is concatenated in a linked list. The MessageQueue object does not need to be created by ourselves, but is managed by a Looper object, and a thread can have at most one MessageQueue. We can get the MessageQueue in the current thread by Looper.myqueue ().
3.Looper
MessageQueue manager, in a thread, if there is a Looper object, there must be a MessageQueue object, and there is only one Looper object and one MessageQueue object. In the Android system, except for the main thread has a default Looper object, other threads default to no Looper object. If you want our newly created thread to have a Looper object, we should first call the Looper.prepare () method, and then call the Looper.loop () method. Typical usage is as follows:
Class Looperthread extends Thread
{public
Handler Mhandler;
public void Run ()
{
looper.prepare ();
Other operations that need to be handled
looper.loop ();
}
If there is a Looper object in our thread, we can get it through Looper.mylooper (), and we can also get the Looper object of the main thread in the current application system by Looper.getmainlooper (). One thing to note in this place is that if the Looper object is in the main thread of the application, Looper.mylooper () and Looper.getmainlooper () get the same object.
4.Handler
The processor of the message. By handler the object we can encapsulate the message object and then add the message object to the MessageQueue via SendMessage (msg), and when MessageQueue loops to the message, The Handlemessage () method of the handler object corresponding to the message object is invoked to process it. Because the message is processed in the Handlemessage () method, we should write a class to inherit from handler and then Handlemessage () to handle the action we need.
Here's how to process messages in Android by tracking code. First paste the test code:
/** * * @author coolszy * */public class Messageservice extends Service {private static final String T
AG = "Messageservice";
private static final int KUKA = 0;
Private Looper Looper;
Private Servicehandler handler; /** * Because processing messages is in the handler Handlemessage () method, we need to write our own class * Inherit from the handler class, and then write the functional code we need in Handlemessage () @author C
Oolszy * * */private Final class Servicehandler extends Handler {public Servicehandler (Looper looper)
{super (Looper);
@Override public void Handlemessage (msg) {//What to determine which message switch (Msg.what) based on the field {Case KUKA://Get the obj field of MSG.
Here we can write the functional code we need LOG.I (TAG, "The obj field of msg:" + msg.obj);
Break
other cases default:break;
//If our service has completed the task, stop service stopself (MSG.ARG1); @Override public void OnCreate () {log.i TAG, MessageservIce-->oncreate () "); Service is run in the main thread by default, and services are generally time-consuming, and if//placed in the main thread, it will affect the program's interaction with the user, so the service////is placed in a separate thread to perform handlerthread thr
EAD = new Handlerthread ("Messagedemothread", Process.thread_priority_background);
Thread.Start ();
Gets the Looper object in the current thread looper = Thread.getlooper ();
Create the handler object, pass the Looper to make the handler,//looper and MessageQueue establish the connection handler = new Servicehandler (looper); @Override public int Onstartcommand (Intent Intent, int flags, int startid) {log.i (TAG, "messageservice-
->onstartcommand () ");
Get an instance of message from the pool msg = Handler.obtainmessage ();
Arg1 saves the ID of the thread, in the Handlemessage () method//We can stop the service MSG.ARG1 = Startid through the Stopself (Startid) method;
MSG logo msg.what = KUKA;
Here I create a Date object that assigns to the OBJ field//In practice we can pass obj the object date = new Date () that we need to work with.
Msg.obj = date;
Add msg to MessageQueue handler.sendmessage (msg);
return start_sticky;
}
@Override public void OnDestroy () {log.i (TAG, Messageservice-->ondestroy ());
@Override public IBinder onbind (Intent Intent) {return null;
}
}
Run Result:
Note: In the test code we use the Handlerthread class, which is a subclass of thread, which will create the Looper object, which eliminates the hassle of writing thread subclasses ourselves and creating Looper.
Below we analyze the running process of the program:
1.onCreate ()
The OnCreate () method is invoked first when the service is started, in which we new a Handlerthread object that provides the thread's name and priority.
Then we call the start () method, and executing the method will call the Handlerthread object's Run () method:
public void Run () {
Mtid = Process.mytid ();
Looper.prepare ();
Synchronized (this) {
mlooper = Looper.mylooper ();
Notifyall ();
}
Process.setthreadpriority (mpriority);
Onlooperprepared ();
Looper.loop ();
Mtid =-1;
}
In the Run () method, the looper that the system adds to the thread also invokes the Looper loop () method:
public static final void loop () {Looper me = Mylooper ();
MessageQueue queue = Me.mqueue;
while (true) {msg = Queue.next ();//might blocks//if (!me.mrun) {//break; } if (msg!= null) {if (Msg.target = = null) {//No target is a magic identifier for the qui
T 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 (); }
}
}
Through the source we can see the loop () method is a dead loop, will not stop getting the message object from the MessageQueue object, if the MessageQueue object does not exist in the Message object, then end this cycle, and then continue to loop If the message object exists, then Msg.target.dispatchMessage (msg) is executed, but what is the value of the. Target field for this msg? Let's stop tracking the source and return to the OnCreate () method. After the thread finishes the start () method, we can get the thread's Looper object, and then a new Servicehandler object, and we pass the Looper object to the Servicehandler constructor to make the handler, Looper and MessageQueue to establish contact.
2.onStartCommand ()
After the OnStart () method is executed, the Onstartcommand () method is executed. First we get an instance of the message from the pool of messages, and then assign values to the arg1, what, obj three fields. Immediately following the call to the SendMessage (msg) method, we trace the source code, which calls the sendmessagedelayed (MSG, 0) method, while sendmessagedelayed () The method then invokes the Sendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis) method, in which we pay attention to the code Msg.target = this, The target of MSG points to this, and this is the Servicehandler object, so the target field of MSG points to the Servicehandler object, and the method calls MessageQueue Enqueuemessage (msg, Uptimemillis) method:
Final Boolean enqueuemessage (msg, long when) {if (msg.when!= 0) {throw new androidruntimeexception
(msg + "This message was already in use."); } if (Msg.target = = null &&!mquitallowed) {throw new RuntimeException ("Main thread not allowed to Qu
It "); } synchronized (this) {if (mquiting) {runtimeexception e = new RuntimeException (Msg.tar
Get + "sending message to a Handler on a dead thread");
LOG.W ("MessageQueue", E.getmessage (), E);
return false;
else if (Msg.target = = null) {mquiting = true;
} Msg.when = when;
LOG.D ("MessageQueue", "enqueing:" + msg);
Message p = mmessages;
if (p = = NULL | | when = = 0 | | When < p.when) {msg.next = P;
Mmessages = msg;
This.notify ();
else {message prev = null; while (P!= null && p.when <= when) {prev = P
p = p.next;
} msg.next = Prev.next;
Prev.next = msg;
This.notify ();
} return true;
}
The main task of this method is to add the message object to the MessageQueue (data structure of the most basic things, their own drawing understanding).
Handler.sendmessage ()-->handler.sendmessagedelayed ()-->handler.sendmessageattime ()-->msg.target = this; Queue.enqueuemessage==> adds msg to message queues
3.handleMessage (msg)
Onstartcommand () After the execution of our service method is completed, then Handlemessage () How to call it? In the loop () method that we analyzed earlier, we did not know what the Target Field code for MSG was, and we now know that it represents the Servicehandler object, Msg.target.dispatchMessage (msg); Represents the execution of the DispatchMessage () method in the Servicehandler object:
public void DispatchMessage (message msg) {
if (msg.callback!= null) {
handlecallback (msg);
} else {
if ( Mcallback!= null) {
if (Mcallback.handlemessage (msg)) {return
;
}
}
Handlemessage (msg);
}
The method first determines whether the callback is empty, we do not see it assigned in the process of tracking, so the callback field is empty, so the Handlemessage () method will eventually be executed, that is, the method of replication in our Servicehandler class. The method will determine which piece of code to execute based on the value of the What field.
At this point, we see, a message through the handler sent, MessageQueue team, looper extraction, and once again back to the embrace of handler. The circle around it also helps us to turn the synchronization operation into an asynchronous operation.
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.