Why does Android suggest message.obtain () instead of just using the new keyword

preface

The Handler is used to send a Message, called a Message object, which can be created using the new keyword or message.obtain ().

/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
Copy the code

Message.obtain() is the first choice to obtain the Message object

Why does Android recommend using the message.obtain () method? Let’s have a look at the mystery of the source code, together to fucking the source code

Source analysis message.obtain () method

/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. * * Public static Message obtain() {synchronized (sPoolSync) {if (sPool! = null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }Copy the code

You can see how if the sPool object is null, a Message object is new; If it is not empty, the first node object of sPool is returned, and sPool is pointed to the next node. So what exactly is sPool?? It is essentially a list of Messages, each containing a next field of type Message object.

You’ve also seen here that Message objects can be fetched in two ways

Conclusion:

  1. If sPool is null, it is obtained directly through new
  2. If sPool is not null, the first node of sPool is returned, and sPool is pointed to its next node

So here’s another question: When was sPool generated and assigned, and when were Message objects added to the sPool pool? Next, we use the source code to navigate to the recycleUnchecked() method, which is called in the recycle() method

RecycleUnchecked () and recycleUnchecked() methods

Public void recycle() {if (isInUse()) {if (gCheckRecycle) {throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; // The current message object can be recycleUnchecked(); }Copy the code
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all Flags = FLAG_IN_USE; // This clears the current message object's member variables (equivalent to a new message). what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null; Synchronized (sPoolSync) {// The current pool size is less than the maximum size, If (sPoolSize < MAX_POOL_SIZE) {next = sPool; if (sPoolSize < MAX_POOL_SIZE) {next = sPool; // Assign the current message to sPool sPool = this; sPoolSize++; }}}Copy the code

The source code for these two methods is relatively easy to read. The basic summary is that when a Message object is reclaimed, its member variable information is cleared, and then the object is added to the sPool pool as the first node.

When is a message object recycled? We can assume that message objects are recycled when they are no longer used; So in the Android message mechanism, it is through the looper.loop () method from the message queue for processing, so let’s go to this method to find the answer we want

Parsing stars. The loop ()

public static void loop() { final Looper me = myLooper(); If (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); // omit some code...... . Final MessageQueue queue = me.mqueue; // omit some code... . // Start a loop to fetch messages from the message queue for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // omit some code...... . Try {/ / the message object to hadler dispatchMessage method for processing message MSG. Target. DispatchMessage (MSG); if (observer ! = null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer ! = null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag ! = 0) { Trace.traceEnd(traceTag); }} // omit some code...... . // Finally... See the familiar method msg.recycleunchecked (); }}Copy the code

As you can see from the source code, when the Message is processed, the Message collection method is called, which adds a Message to sPool

conclusion

A sPool object is maintained within the Message object, which is essentially a list of messages. The default length is 50. In messaging, each time the Message object is obtained (), the sPool is empty, the new object is obtained; if the sPool is not empty, the Message object of the first node is obtained. Then, when polling for messages in looper.loop (), each time a message is processed, it is inserted into the first node of sPool. The purpose of this design is to maintain a Message pool and, if there are reusable messages in the pool, to reuse them, avoiding the memory and performance costs of creating and destroying messages frequently.