459 lines
14 KiB
Java
459 lines
14 KiB
Java
|
/*
|
||
|
* Copyright (C) 2006 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.os;
|
||
|
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.util.TimeUtils;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Defines a message containing a description and arbitrary data object that can be
|
||
|
* sent to a {@link Handler}. This object contains two extra int fields and an
|
||
|
* extra object field that allow you to not do allocations in many cases.
|
||
|
*
|
||
|
* <p class="note">While the constructor of Message is public, the best way to get
|
||
|
* one of these is to call {@link #obtain Message.obtain()} or one of the
|
||
|
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
|
||
|
* them from a pool of recycled objects.</p>
|
||
|
*/
|
||
|
public final class Message implements Parcelable {
|
||
|
/**
|
||
|
* User-defined message code so that the recipient can identify
|
||
|
* what this message is about. Each {@link Handler} has its own name-space
|
||
|
* for message codes, so you do not need to worry about yours conflicting
|
||
|
* with other handlers.
|
||
|
*/
|
||
|
public int what;
|
||
|
|
||
|
/**
|
||
|
* arg1 and arg2 are lower-cost alternatives to using
|
||
|
* {@link #setData(Bundle) setData()} if you only need to store a
|
||
|
* few integer values.
|
||
|
*/
|
||
|
public int arg1;
|
||
|
|
||
|
/**
|
||
|
* arg1 and arg2 are lower-cost alternatives to using
|
||
|
* {@link #setData(Bundle) setData()} if you only need to store a
|
||
|
* few integer values.
|
||
|
*/
|
||
|
public int arg2;
|
||
|
|
||
|
/**
|
||
|
* An arbitrary object to send to the recipient. When using
|
||
|
* {@link Messenger} to send the message across processes this can only
|
||
|
* be non-null if it contains a Parcelable of a framework class (not one
|
||
|
* implemented by the application). For other data transfer use
|
||
|
* {@link #setData}.
|
||
|
*
|
||
|
* <p>Note that Parcelable objects here are not supported prior to
|
||
|
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
|
||
|
*/
|
||
|
public Object obj;
|
||
|
|
||
|
/**
|
||
|
* Optional Messenger where replies to this message can be sent. The
|
||
|
* semantics of exactly how this is used are up to the sender and
|
||
|
* receiver.
|
||
|
*/
|
||
|
public Messenger replyTo;
|
||
|
|
||
|
/*package*/ long when;
|
||
|
|
||
|
/*package*/ Bundle data;
|
||
|
|
||
|
/*package*/ Handler target;
|
||
|
|
||
|
/*package*/ Runnable callback;
|
||
|
|
||
|
// sometimes we store linked lists of these things
|
||
|
/*package*/ Message next;
|
||
|
|
||
|
private static Object mPoolSync = new Object();
|
||
|
private static Message mPool;
|
||
|
private static int mPoolSize = 0;
|
||
|
|
||
|
private static final int MAX_POOL_SIZE = 10;
|
||
|
|
||
|
/**
|
||
|
* Return a new Message instance from the global pool. Allows us to
|
||
|
* avoid allocating new objects in many cases.
|
||
|
*/
|
||
|
public static Message obtain() {
|
||
|
synchronized (mPoolSync) {
|
||
|
if (mPool != null) {
|
||
|
Message m = mPool;
|
||
|
mPool = m.next;
|
||
|
m.next = null;
|
||
|
mPoolSize--;
|
||
|
return m;
|
||
|
}
|
||
|
}
|
||
|
return new Message();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but copies the values of an existing
|
||
|
* message (including its target) into the new one.
|
||
|
* @param orig Original message to copy.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Message orig) {
|
||
|
Message m = obtain();
|
||
|
m.what = orig.what;
|
||
|
m.arg1 = orig.arg1;
|
||
|
m.arg2 = orig.arg2;
|
||
|
m.obj = orig.obj;
|
||
|
m.replyTo = orig.replyTo;
|
||
|
if (orig.data != null) {
|
||
|
m.data = new Bundle(orig.data);
|
||
|
}
|
||
|
m.target = orig.target;
|
||
|
m.callback = orig.callback;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
|
||
|
* @param h Handler to assign to the returned Message object's <em>target</em> member.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
|
||
|
* the Message that is returned.
|
||
|
* @param h Handler to assign to the returned Message object's <em>target</em> member.
|
||
|
* @param callback Runnable that will execute when the message is handled.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h, Runnable callback) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
m.callback = callback;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but sets the values for both <em>target</em> and
|
||
|
* <em>what</em> members on the Message.
|
||
|
* @param h Value to assign to the <em>target</em> member.
|
||
|
* @param what Value to assign to the <em>what</em> member.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h, int what) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
m.what = what;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
|
||
|
* members.
|
||
|
* @param h The <em>target</em> value to set.
|
||
|
* @param what The <em>what</em> value to set.
|
||
|
* @param obj The <em>object</em> method to set.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h, int what, Object obj) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
m.what = what;
|
||
|
m.obj = obj;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
|
||
|
* <em>arg1</em>, and <em>arg2</em> members.
|
||
|
*
|
||
|
* @param h The <em>target</em> value to set.
|
||
|
* @param what The <em>what</em> value to set.
|
||
|
* @param arg1 The <em>arg1</em> value to set.
|
||
|
* @param arg2 The <em>arg2</em> value to set.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h, int what, int arg1, int arg2) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
m.what = what;
|
||
|
m.arg1 = arg1;
|
||
|
m.arg2 = arg2;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
|
||
|
* <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
|
||
|
*
|
||
|
* @param h The <em>target</em> value to set.
|
||
|
* @param what The <em>what</em> value to set.
|
||
|
* @param arg1 The <em>arg1</em> value to set.
|
||
|
* @param arg2 The <em>arg2</em> value to set.
|
||
|
* @param obj The <em>obj</em> value to set.
|
||
|
* @return A Message object from the global pool.
|
||
|
*/
|
||
|
public static Message obtain(Handler h, int what,
|
||
|
int arg1, int arg2, Object obj) {
|
||
|
Message m = obtain();
|
||
|
m.target = h;
|
||
|
m.what = what;
|
||
|
m.arg1 = arg1;
|
||
|
m.arg2 = arg2;
|
||
|
m.obj = obj;
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a Message instance to the global pool. You MUST NOT touch
|
||
|
* the Message after calling this function -- it has effectively been
|
||
|
* freed.
|
||
|
*/
|
||
|
public void recycle() {
|
||
|
synchronized (mPoolSync) {
|
||
|
if (mPoolSize < MAX_POOL_SIZE) {
|
||
|
clearForRecycle();
|
||
|
|
||
|
next = mPool;
|
||
|
mPool = this;
|
||
|
mPoolSize++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Make this message like o. Performs a shallow copy of the data field.
|
||
|
* Does not copy the linked list fields, nor the timestamp or
|
||
|
* target/callback of the original message.
|
||
|
*/
|
||
|
public void copyFrom(Message o) {
|
||
|
this.what = o.what;
|
||
|
this.arg1 = o.arg1;
|
||
|
this.arg2 = o.arg2;
|
||
|
this.obj = o.obj;
|
||
|
this.replyTo = o.replyTo;
|
||
|
|
||
|
if (o.data != null) {
|
||
|
this.data = (Bundle) o.data.clone();
|
||
|
} else {
|
||
|
this.data = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the targeted delivery time of this message, in milliseconds.
|
||
|
*/
|
||
|
public long getWhen() {
|
||
|
return when;
|
||
|
}
|
||
|
|
||
|
public void setTarget(Handler target) {
|
||
|
this.target = target;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve the a {@link android.os.Handler Handler} implementation that
|
||
|
* will receive this message. The object must implement
|
||
|
* {@link android.os.Handler#handleMessage(android.os.Message)
|
||
|
* Handler.handleMessage()}. Each Handler has its own name-space for
|
||
|
* message codes, so you do not need to
|
||
|
* worry about yours conflicting with other handlers.
|
||
|
*/
|
||
|
public Handler getTarget() {
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve callback object that will execute when this message is handled.
|
||
|
* This object must implement Runnable. This is called by
|
||
|
* the <em>target</em> {@link Handler} that is receiving this Message to
|
||
|
* dispatch it. If
|
||
|
* not set, the message will be dispatched to the receiving Handler's
|
||
|
* {@link Handler#handleMessage(Message Handler.handleMessage())}.
|
||
|
*/
|
||
|
public Runnable getCallback() {
|
||
|
return callback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Obtains a Bundle of arbitrary data associated with this
|
||
|
* event, lazily creating it if necessary. Set this value by calling
|
||
|
* {@link #setData(Bundle)}. Note that when transferring data across
|
||
|
* processes via {@link Messenger}, you will need to set your ClassLoader
|
||
|
* on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
|
||
|
* Bundle.setClassLoader()} so that it can instantiate your objects when
|
||
|
* you retrieve them.
|
||
|
* @see #peekData()
|
||
|
* @see #setData(Bundle)
|
||
|
*/
|
||
|
public Bundle getData() {
|
||
|
if (data == null) {
|
||
|
data = new Bundle();
|
||
|
}
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Like getData(), but does not lazily create the Bundle. A null
|
||
|
* is returned if the Bundle does not already exist. See
|
||
|
* {@link #getData} for further information on this.
|
||
|
* @see #getData()
|
||
|
* @see #setData(Bundle)
|
||
|
*/
|
||
|
public Bundle peekData() {
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
|
||
|
* as a lower cost way to send a few simple integer values, if you can.
|
||
|
* @see #getData()
|
||
|
* @see #peekData()
|
||
|
*/
|
||
|
public void setData(Bundle data) {
|
||
|
this.data = data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sends this Message to the Handler specified by {@link #getTarget}.
|
||
|
* Throws a null pointer exception if this field has not been set.
|
||
|
*/
|
||
|
public void sendToTarget() {
|
||
|
target.sendMessage(this);
|
||
|
}
|
||
|
|
||
|
/*package*/ void clearForRecycle() {
|
||
|
what = 0;
|
||
|
arg1 = 0;
|
||
|
arg2 = 0;
|
||
|
obj = null;
|
||
|
replyTo = null;
|
||
|
when = 0;
|
||
|
target = null;
|
||
|
callback = null;
|
||
|
data = null;
|
||
|
}
|
||
|
|
||
|
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
|
||
|
*/
|
||
|
public Message() {
|
||
|
}
|
||
|
|
||
|
public String toString() {
|
||
|
return toString(SystemClock.uptimeMillis());
|
||
|
}
|
||
|
|
||
|
String toString(long now) {
|
||
|
StringBuilder b = new StringBuilder();
|
||
|
|
||
|
b.append("{ what=");
|
||
|
b.append(what);
|
||
|
|
||
|
b.append(" when=");
|
||
|
TimeUtils.formatDuration(when-now, b);
|
||
|
|
||
|
if (arg1 != 0) {
|
||
|
b.append(" arg1=");
|
||
|
b.append(arg1);
|
||
|
}
|
||
|
|
||
|
if (arg2 != 0) {
|
||
|
b.append(" arg2=");
|
||
|
b.append(arg2);
|
||
|
}
|
||
|
|
||
|
if (obj != null) {
|
||
|
b.append(" obj=");
|
||
|
b.append(obj);
|
||
|
}
|
||
|
|
||
|
b.append(" }");
|
||
|
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
public static final Parcelable.Creator<Message> CREATOR
|
||
|
= new Parcelable.Creator<Message>() {
|
||
|
public Message createFromParcel(Parcel source) {
|
||
|
Message msg = Message.obtain();
|
||
|
msg.readFromParcel(source);
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
public Message[] newArray(int size) {
|
||
|
return new Message[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
if (callback != null) {
|
||
|
throw new RuntimeException(
|
||
|
"Can't marshal callbacks across processes.");
|
||
|
}
|
||
|
dest.writeInt(what);
|
||
|
dest.writeInt(arg1);
|
||
|
dest.writeInt(arg2);
|
||
|
if (obj != null) {
|
||
|
try {
|
||
|
Parcelable p = (Parcelable)obj;
|
||
|
dest.writeInt(1);
|
||
|
dest.writeParcelable(p, flags);
|
||
|
} catch (ClassCastException e) {
|
||
|
throw new RuntimeException(
|
||
|
"Can't marshal non-Parcelable objects across processes.");
|
||
|
}
|
||
|
} else {
|
||
|
dest.writeInt(0);
|
||
|
}
|
||
|
dest.writeLong(when);
|
||
|
dest.writeBundle(data);
|
||
|
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
|
||
|
}
|
||
|
|
||
|
private final void readFromParcel(Parcel source) {
|
||
|
what = source.readInt();
|
||
|
arg1 = source.readInt();
|
||
|
arg2 = source.readInt();
|
||
|
if (source.readInt() != 0) {
|
||
|
obj = source.readParcelable(getClass().getClassLoader());
|
||
|
}
|
||
|
when = source.readLong();
|
||
|
data = source.readBundle();
|
||
|
replyTo = Messenger.readMessengerOrNullFromParcel(source);
|
||
|
}
|
||
|
}
|
||
|
|