zoukankan      html  css  js  c++  java
  • Android Handler机制(一)---Message源码分析

    Message:

    定义:

    public final class Message implements Parcelable 
    

    Message类是个final类,就是说不能被继承,同时Message类实现了Parcelable接口,我们知道android提供了一种新的类型:Parcel。本类被用作封装数据的容器,是链表结构,有个属性next和sPool,这两个变量是不同的,具体什么不同看下文。

    文档描述:

    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.  
    

    定义一个包含任意类型的描述数据对象,此对象可以发送给Handler。对象包含两个额外的int字段和一个额外的对象字段,这样可以使得在很多情况下不用做分配工作。尽管Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。

    1.看一下全局变量:有好多存数据的对象。

    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    /*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 = 50;
    
    private static boolean gCheckRecycle = true;
    1. what:用户定义消息代码以便收件人可以识别这是哪一个Message。每个Handler用它自己的名称空间为消息代码,所以您不需要担心你的Handler与其他handler冲突。
    2. arg1、arg2:如果只是想向message内放一些整数值,可以使用arg1和arg2来代替setData方法。
    3. obj:发送给接收器的任意对象。当使用Message对象在线程间传递消息时,如果它包含一个Parcelable的结构类(不是由应用程序实现的类),此字段必须为非空(non-null)。其他的数据传输则使用setData(Bundle)方法。注意Parcelable对象是从FROYO版本以后才开始支持的。
    4. replyTo:指明此message发送到何处的可选Messenger对象。具体的使用方法由发送者和接受者决定。
    5. FLAG_IN_USE:判断Message是否在使用( default 包内可见)
    6. FLAG_ASYNCHRONOUS:如果设置message是异步的。
    7. FLAGS_TO_CLEAR_ON_COPY_FROM:明确在copyFrom方法
    8. 其他参数都比较简单,不详述

    Obtain方法:

     

    //从全局池中返回一个新的Message实例。在大多数情况下这样可以避免分配新的对象。
    //是一个静态方法
    public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    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;
            m.sendingUid = orig.sendingUid;
            if (orig.data != null) {
                m.data = new Bundle(orig.data);
            }
            m.target = orig.target;
            m.callback = orig.callback;
    
            return m;
        }
     /**
         设置target
         */
    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 of the <em>target</em>, <em>what</em>, 
         * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
          。。。。
         * @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实例加上各种参数。代码一目了然。。。

    recycle():回收当前message到全局池

     

    /**
         * Return a Message instance to the global pool.
         * <p>
         * You MUST NOT touch the Message after calling this function because it has
         * effectively been freed.  It is an error to recycle a message that is currently
         * enqueued or that is in the process of being delivered to a Handler.
         * </p>
         */
        public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
        }
    
        /**
         * Recycles a Message that may be in-use.
         * Used internally by the MessageQueue and Looper when disposing of queued Messages.
         */
        void recycleUnchecked() {
            // Mark the message as in use while it remains in the recycled object pool.
            // Clear out all other details.
            flags = FLAG_IN_USE;
            what = 0;
            arg1 = 0;
            arg2 = 0;
            obj = null;
            replyTo = null;
            sendingUid = -1;
            when = 0;
            target = null;
            callback = null;
            data = null;
    
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    

    向全局池中返回一个Message实例。一定不能在调用此函数后再使用Message——它实际上已经被释放。

    getWhen:

     /**
         * Return the targeted delivery time of this message, in milliseconds.
         */
        public long getWhen() {
            return when;
        }
    

    返回此消息的传输时间,以毫秒为单位。

     setTarget,getTarget:

    //设置handler和返回handler
    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;
        }
    

    获取将接收此消息的Handler对象。此对象必须要实现Handler.handleMessage()方法。每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突。

    setData:

     设置一个可以是任何类型值的bundle。

    /**
         * Sets a Bundle of arbitrary data values. Use arg1 and arg2 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;
        }
    

      getData,peekData

     public Bundle getData() {
            if (data == null) {
                data = new Bundle();
            }
            
            return data;
        }
    public Bundle peekData() {
            return data;
    }
    

    发送消息的一些方法:

    /**向Handler发送此消息,getTarget()方法可以获取此Handler。如果这个字段没有设置会抛出个空指针异常。
         * 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);
        }  

    构造方法:

     /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
        */
        public Message() {
        }
    //推荐使用Message.obtain()

    writeToParcel:

    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);
            dest.writeInt(sendingUid);
        }
    

     将类的数据写入外部提供的Parcel中和从Parcel中读取数据。

    Message结束。。。。

  • 相关阅读:
    Oracle SQL语句收集
    SqlParameter In 查询
    SQL 性能优化
    Entity Framework
    【XLL API 函数】 xlfSetName
    【XLL API 函数】xlfUnregister (Form 2)
    【XLL API 函数】xlfUnregister (Form 1)
    【Excel 4.0 函数】REGISTER 的两种形式以及VBA等效语句
    【Excel 4.0 函数】REGISTER
    【Bochs 官方手册翻译】 第一章 Bochs介绍
  • 原文地址:https://www.cnblogs.com/jycboy/p/5786551.html
Copyright © 2011-2022 走看看