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