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