Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.os;
     18 
     19 import android.os.Bundle;
     20 import android.os.Parcel;
     21 import android.os.Parcelable;
     22 
     23 /**
     24  *
     25  * Defines a message containing a description and arbitrary data object that can be
     26  * sent to a {@link Handler}.  This object contains two extra int fields and an
     27  * extra object field that allow you to not do allocations in many cases.
     28  *
     29  * <p class="note">While the constructor of Message is public, the best way to get
     30  * one of these is to call {@link #obtain Message.obtain()} or one of the
     31  * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
     32  * them from a pool of recycled objects.</p>
     33  */
     34 public final class Message implements Parcelable {
     35     /**
     36      * User-defined message code so that the recipient can identify
     37      * what this message is about. Each {@link Handler} has its own name-space
     38      * for message codes, so you do not need to worry about yours conflicting
     39      * with other handlers.
     40      */
     41     public int what;
     42 
     43     /**
     44      * arg1 and arg2 are lower-cost alternatives to using
     45      * {@link #setData(Bundle) setData()} if you only need to store a
     46      * few integer values.
     47      */
     48     public int arg1;
     49 
     50     /**
     51      * arg1 and arg2 are lower-cost alternatives to using
     52      * {@link #setData(Bundle) setData()} if you only need to store a
     53      * few integer values.
     54      */
     55     public int arg2;
     56 
     57     /**
     58      * An arbitrary object to send to the recipient.  When using
     59      * {@link Messenger} to send the message across processes this can only
     60      * be non-null if it contains a Parcelable of a framework class (not one
     61      * implemented by the application).   For other data transfer use
     62      * {@link #setData}.
     63      *
     64      * <p>Note that Parcelable objects here are not supported prior to
     65      * the {@link android.os.Build.VERSION_CODES#FROYO} release.
     66      */
     67     public Object obj;
     68 
     69     /**
     70      * Optional Messenger where replies to this message can be sent.  The
     71      * semantics of exactly how this is used are up to the sender and
     72      * receiver.
     73      */
     74     public Messenger replyTo;
     75 
     76     /*package*/ long when;
     77 
     78     /*package*/ Bundle data;
     79 
     80     /*package*/ Handler target;
     81 
     82     /*package*/ Runnable callback;
     83 
     84     // sometimes we store linked lists of these things
     85     /*package*/ Message next;
     86 
     87     private static Object mPoolSync = new Object();
     88     private static Message mPool;
     89     private static int mPoolSize = 0;
     90 
     91     private static final int MAX_POOL_SIZE = 10;
     92 
     93     /**
     94      * Return a new Message instance from the global pool. Allows us to
     95      * avoid allocating new objects in many cases.
     96      */
     97     public static Message obtain() {
     98         synchronized (mPoolSync) {
     99             if (mPool != null) {
    100                 Message m = mPool;
    101                 mPool = m.next;
    102                 m.next = null;
    103                 return m;
    104             }
    105         }
    106         return new Message();
    107     }
    108 
    109     /**
    110      * Same as {@link #obtain()}, but copies the values of an existing
    111      * message (including its target) into the new one.
    112      * @param orig Original message to copy.
    113      * @return A Message object from the global pool.
    114      */
    115     public static Message obtain(Message orig) {
    116         Message m = obtain();
    117         m.what = orig.what;
    118         m.arg1 = orig.arg1;
    119         m.arg2 = orig.arg2;
    120         m.obj = orig.obj;
    121         m.replyTo = orig.replyTo;
    122         if (orig.data != null) {
    123             m.data = new Bundle(orig.data);
    124         }
    125         m.target = orig.target;
    126         m.callback = orig.callback;
    127 
    128         return m;
    129     }
    130 
    131     /**
    132      * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
    133      * @param h  Handler to assign to the returned Message object's <em>target</em> member.
    134      * @return A Message object from the global pool.
    135      */
    136     public static Message obtain(Handler h) {
    137         Message m = obtain();
    138         m.target = h;
    139 
    140         return m;
    141     }
    142 
    143     /**
    144      * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
    145      * the Message that is returned.
    146      * @param h  Handler to assign to the returned Message object's <em>target</em> member.
    147      * @param callback Runnable that will execute when the message is handled.
    148      * @return A Message object from the global pool.
    149      */
    150     public static Message obtain(Handler h, Runnable callback) {
    151         Message m = obtain();
    152         m.target = h;
    153         m.callback = callback;
    154 
    155         return m;
    156     }
    157 
    158     /**
    159      * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
    160      * <em>what</em> members on the Message.
    161      * @param h  Value to assign to the <em>target</em> member.
    162      * @param what  Value to assign to the <em>what</em> member.
    163      * @return A Message object from the global pool.
    164      */
    165     public static Message obtain(Handler h, int what) {
    166         Message m = obtain();
    167         m.target = h;
    168         m.what = what;
    169 
    170         return m;
    171     }
    172 
    173     /**
    174      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
    175      * members.
    176      * @param h  The <em>target</em> value to set.
    177      * @param what  The <em>what</em> value to set.
    178      * @param obj  The <em>object</em> method to set.
    179      * @return  A Message object from the global pool.
    180      */
    181     public static Message obtain(Handler h, int what, Object obj) {
    182         Message m = obtain();
    183         m.target = h;
    184         m.what = what;
    185         m.obj = obj;
    186 
    187         return m;
    188     }
    189 
    190     /**
    191      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
    192      * <em>arg1</em>, and <em>arg2</em> members.
    193      *
    194      * @param h  The <em>target</em> value to set.
    195      * @param what  The <em>what</em> value to set.
    196      * @param arg1  The <em>arg1</em> value to set.
    197      * @param arg2  The <em>arg2</em> value to set.
    198      * @return  A Message object from the global pool.
    199      */
    200     public static Message obtain(Handler h, int what, int arg1, int arg2) {
    201         Message m = obtain();
    202         m.target = h;
    203         m.what = what;
    204         m.arg1 = arg1;
    205         m.arg2 = arg2;
    206 
    207         return m;
    208     }
    209 
    210     /**
    211      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
    212      * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
    213      *
    214      * @param h  The <em>target</em> value to set.
    215      * @param what  The <em>what</em> value to set.
    216      * @param arg1  The <em>arg1</em> value to set.
    217      * @param arg2  The <em>arg2</em> value to set.
    218      * @param obj  The <em>obj</em> value to set.
    219      * @return  A Message object from the global pool.
    220      */
    221     public static Message obtain(Handler h, int what,
    222             int arg1, int arg2, Object obj) {
    223         Message m = obtain();
    224         m.target = h;
    225         m.what = what;
    226         m.arg1 = arg1;
    227         m.arg2 = arg2;
    228         m.obj = obj;
    229 
    230         return m;
    231     }
    232 
    233     /**
    234      * Return a Message instance to the global pool.  You MUST NOT touch
    235      * the Message after calling this function -- it has effectively been
    236      * freed.
    237      */
    238     public void recycle() {
    239         synchronized (mPoolSync) {
    240             if (mPoolSize < MAX_POOL_SIZE) {
    241                 clearForRecycle();
    242 
    243                 next = mPool;
    244                 mPool = this;
    245             }
    246         }
    247     }
    248 
    249     /**
    250      * Make this message like o.  Performs a shallow copy of the data field.
    251      * Does not copy the linked list fields, nor the timestamp or
    252      * target/callback of the original message.
    253      */
    254     public void copyFrom(Message o) {
    255         this.what = o.what;
    256         this.arg1 = o.arg1;
    257         this.arg2 = o.arg2;
    258         this.obj = o.obj;
    259         this.replyTo = o.replyTo;
    260 
    261         if (o.data != null) {
    262             this.data = (Bundle) o.data.clone();
    263         } else {
    264             this.data = null;
    265         }
    266     }
    267 
    268     /**
    269      * Return the targeted delivery time of this message, in milliseconds.
    270      */
    271     public long getWhen() {
    272         return when;
    273     }
    274 
    275     public void setTarget(Handler target) {
    276         this.target = target;
    277     }
    278 
    279     /**
    280      * Retrieve the a {@link android.os.Handler Handler} implementation that
    281      * will receive this message. The object must implement
    282      * {@link android.os.Handler#handleMessage(android.os.Message)
    283      * Handler.handleMessage()}. Each Handler has its own name-space for
    284      * message codes, so you do not need to
    285      * worry about yours conflicting with other handlers.
    286      */
    287     public Handler getTarget() {
    288         return target;
    289     }
    290 
    291     /**
    292      * Retrieve callback object that will execute when this message is handled.
    293      * This object must implement Runnable. This is called by
    294      * the <em>target</em> {@link Handler} that is receiving this Message to
    295      * dispatch it.  If
    296      * not set, the message will be dispatched to the receiving Handler's
    297      * {@link Handler#handleMessage(Message Handler.handleMessage())}.
    298      */
    299     public Runnable getCallback() {
    300         return callback;
    301     }
    302 
    303     /**
    304      * Obtains a Bundle of arbitrary data associated with this
    305      * event, lazily creating it if necessary. Set this value by calling
    306      * {@link #setData(Bundle)}.  Note that when transferring data across
    307      * processes via {@link Messenger}, you will need to set your ClassLoader
    308      * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
    309      * Bundle.setClassLoader()} so that it can instantiate your objects when
    310      * you retrieve them.
    311      * @see #peekData()
    312      * @see #setData(Bundle)
    313      */
    314     public Bundle getData() {
    315         if (data == null) {
    316             data = new Bundle();
    317         }
    318 
    319         return data;
    320     }
    321 
    322     /**
    323      * Like getData(), but does not lazily create the Bundle.  A null
    324      * is returned if the Bundle does not already exist.  See
    325      * {@link #getData} for further information on this.
    326      * @see #getData()
    327      * @see #setData(Bundle)
    328      */
    329     public Bundle peekData() {
    330         return data;
    331     }
    332 
    333     /**
    334      * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
    335      * as a lower cost way to send a few simple integer values, if you can.
    336      * @see #getData()
    337      * @see #peekData()
    338      */
    339     public void setData(Bundle data) {
    340         this.data = data;
    341     }
    342 
    343     /**
    344      * Sends this Message to the Handler specified by {@link #getTarget}.
    345      * Throws a null pointer exception if this field has not been set.
    346      */
    347     public void sendToTarget() {
    348         target.sendMessage(this);
    349     }
    350 
    351     /*package*/ void clearForRecycle() {
    352         what = 0;
    353         arg1 = 0;
    354         arg2 = 0;
    355         obj = null;
    356         replyTo = null;
    357         when = 0;
    358         target = null;
    359         callback = null;
    360         data = null;
    361     }
    362 
    363     /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
    364     */
    365     public Message() {
    366     }
    367 
    368     public String toString() {
    369         StringBuilder   b = new StringBuilder();
    370 
    371         b.append("{ what=");
    372         b.append(what);
    373 
    374         b.append(" when=");
    375         b.append(when);
    376 
    377         if (arg1 != 0) {
    378             b.append(" arg1=");
    379             b.append(arg1);
    380         }
    381 
    382         if (arg2 != 0) {
    383             b.append(" arg2=");
    384             b.append(arg2);
    385         }
    386 
    387         if (obj != null) {
    388             b.append(" obj=");
    389             b.append(obj);
    390         }
    391 
    392         b.append(" }");
    393 
    394         return b.toString();
    395     }
    396 
    397     public static final Parcelable.Creator<Message> CREATOR
    398             = new Parcelable.Creator<Message>() {
    399         public Message createFromParcel(Parcel source) {
    400             Message msg = Message.obtain();
    401             msg.readFromParcel(source);
    402             return msg;
    403         }
    404 
    405         public Message[] newArray(int size) {
    406             return new Message[size];
    407         }
    408     };
    409 
    410     public int describeContents() {
    411         return 0;
    412     }
    413 
    414     public void writeToParcel(Parcel dest, int flags) {
    415         if (callback != null) {
    416             throw new RuntimeException(
    417                 "Can't marshal callbacks across processes.");
    418         }
    419         dest.writeInt(what);
    420         dest.writeInt(arg1);
    421         dest.writeInt(arg2);
    422         if (obj != null) {
    423             try {
    424                 Parcelable p = (Parcelable)obj;
    425                 dest.writeInt(1);
    426                 dest.writeParcelable(p, flags);
    427             } catch (ClassCastException e) {
    428                 throw new RuntimeException(
    429                     "Can't marshal non-Parcelable objects across processes.");
    430             }
    431         } else {
    432             dest.writeInt(0);
    433         }
    434         dest.writeLong(when);
    435         dest.writeBundle(data);
    436         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
    437     }
    438 
    439     private final void readFromParcel(Parcel source) {
    440         what = source.readInt();
    441         arg1 = source.readInt();
    442         arg2 = source.readInt();
    443         if (source.readInt() != 0) {
    444             obj = source.readParcelable(getClass().getClassLoader());
    445         }
    446         when = source.readLong();
    447         data = source.readBundle();
    448         replyTo = Messenger.readMessengerOrNullFromParcel(source);
    449     }
    450 }
    451 
    452