Message.java revision 75288fa1a4ee4886959af7243995d8afd9c3c905
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
17package android.os;
18
19import android.os.Bundle;
20import android.os.Parcel;
21import 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 */
34public 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