android源码解析--Message
看下类定义:
- Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.
- While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.
定义一个包含任意类型的描述数据对象,此对象可以发送给Handler。对象包含两个额外的int字段和一个额外的对象字段,这样可以使得在很多情况下不用做分配工作。尽管Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。
- public final class Message implements Parcelable
Message类是个final类,就是说不能被继承,同时Message类实现了Parcelable接口,我们知道android提供了一种新的类型:Parcel。本类被用作封装数据的容器,封装后的数据可以通过Intent或IPC传递。 除了基本类型以外,只有实现了Parcelable接口的类才能被放入Parcel中。
看一下全局变量:
- /**
- * 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;
- /** If set message is in use */
- /*package*/ static final int FLAG_IN_USE = 1;
- /** Flags reserved for future use (All are reserved for now) */
- /*package*/ static final int FLAGS_RESERVED = ~FLAG_IN_USE;
- /** Flags to clear in the copyFrom method */
- /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAGS_RESERVED | FLAG_IN_USE;
- /*package*/ int flags;
- /*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 final Object sPoolSync = new Object();
- private static Message sPool;
- private static int sPoolSize = 0;
- private static final int MAX_POOL_SIZE = 10;
- what:用户定义消息代码以便收件人可以识别这是哪一个Message。每个Handler用它自己的名称空间为消息代码,所以您不需要担心你的Handler与其他handler冲突。
- arg1、arg2:如果只是想向message内放一些整数值,可以使用arg1和arg2来代替setData方法。
- obj:发送给接收器的任意对象。当使用Message对象在线程间传递消息时,如果它包含一个Parcelable的结构类(不是由应用程序实现的类),此字段必须为非空(non-null)。其他的数据传输则使用setData(Bundle)方法。注意Parcelable对象是从FROYO版本以后才开始支持的。
- replyTo:指明此message发送到何处的可选Messenger对象。具体的使用方法由发送者和接受者决定。
- FLAG_IN_USE:判断Message是否在使用( default 包内可见)
- FLAGS_RESERVED:留个将来使用??
- FLAGS_TO_CLEAR_ON_COPY_FROM:明确在copyFrom方法
- 其他参数都比较简单,不详述
下面看obtain方法:
- /**
- * Return a new Message instance from the global pool. Allows us to
- * avoid allocating new objects in many cases.
- */
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
从全局池中返回一个新的Message实例。在大多数情况下这样可以避免分配新的对象。
在看它一系列的重载方法:
- /**
- * 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;
- }
都是先调用obtain()方法,然后把获取的Message实例加上各种参数。
- /**
- * 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() {
- clearForRecycle();
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
向全局池中返回一个Message实例。一定不能在调用此函数后再使用Message——它会立即被释放。
- /**
- * 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.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
- 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;
- }
- }
使此message跟参数o相似。浅拷贝数据域。不拷贝源message的链表字段,时间戳和目标/回调。
- /**
- * Return the targeted delivery time of this message, in milliseconds.
- */
- public long getWhen() {
- return when;
- }
设置一个任意数据值的Bundle对象。如果可以,使用arg1和arg2域发送一些整型值以减少消耗。
参考
getData()
peekData()
返回此消息的传输时间,以毫秒为单位。
- public void setTarget(Handler target) {
- this.target = target;
- }
设置目标handler(接收其消息的Handler)。
- /**
- * 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;
- }
获取将接收此消息的Handler对象。此对象必须要实现Handler.handleMessage()方法。每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突。
- /**
- * 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;
- }
获取回调对象,此对象会在message处理时执行。此对象必须实现Runnable接口。回调由接收此消息并分发的目标handler调用。如果没有设置回调,此消息会分发到接收handler的handleMessage(Message)。
- /**
- * 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;
- }
获取附加在此事件上的任意数据的Bundle对象,需要时延迟创建。通过调用setData(Bundle)来设置Bundle的值。需要注意的是,如果通过Messenger对象在进程间传递数据时,需要调用Bundle类的Bundle.setClassLoader()方法来设置ClassLoader,这样当接收到消息时可以实例化Bundle里的对象。
参考
peekData()
setData(Bundle)
- /**
- * 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;
- }
与getData()相似,但是并不延迟创建Bundle。如果Bundle对象不存在返回null。更多信息见getData()。
参考
getData()
setData(Bundle)
- /**
- * 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;
- }
设置一个任意数据值的Bundle对象。如果可以,使用arg1和arg2域发送一些整型值以减少消耗。
参考
getData()
peekData()
- /**
- * 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);
- }
向Handler发送此消息,getTarget()方法可以获取此Handler。如果这个字段没有设置会抛出个空指针异常。
- void clearForRecycle() {
- flags = 0;
- what = 0;
- arg1 = 0;
- arg2 = 0;
- obj = null;
- replyTo = null;
- when = 0;
- target = null;
- callback = null;
- data = null;
- }
default方法,包内可见,清空所有数据。
- /*package*/ boolean isInUse() {
- return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
- }
- /*package*/ void markInUse() {
- flags |= FLAG_IN_USE;
- }
获取Message是否在使用和标记为使用。
构造方法:
- /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
- */
- public Message() {
- }
跟推荐使用Message.obtain()方法。
toString方法:
- 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;
- }
描述了包含在Parcelable对象排列信息中的特殊对象的类型。
返回值
一个标志位,表明Parcelable对象特殊对象类型集合的排列。
- 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);
- }
将类的数据写入外部提供的Parcel中和从Parcel中读取数据。