android消息处理机制

Android消息处理涉及到的类有Looper,MessageQueue,Handler,Thread。下面看下它们之间的关系。

Looper

默认Thread是没有message loop的,要创建一个,在Thread的run()中执行Looper.prepare(),调用Looper.loop(),使Thread一直运行来处理消息,要让Thread停止运行,调用loop quit。

下面是示例代码

  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

看看调用Looper.prepare()做了什么。

     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

在prepare()中,创建了Looper实例,该实例和当前Thread关联起来,放在ThreadLocal中。

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
    }
在Looper的构造函数中创建了MessageQueue的实例。


看Looper.loop()的源码

 /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();
        }
    }

queue.next()如果没有消息,会block,如果queue quit了其返回Message会是null,loop此时也会结束。拿到Message,则
msg.target.dispatchMessage(msg);


看Handler的dispatchMessage():

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

如果Message没有callback,Handler的mCallback返回的是false,最终会执行handleMessage()。

当处理完一条Message后,其会被回收。


MessageQueue

MessageQueue顾名思义,用来存放Messge,Messge不是直接添加到MessageQueue,通过Handler添加的,sendMessage(),sendMessageDelayed()等方法。

通过Looper.myQueue()可以得到MessageQueue的实例。


Handler

先看构造方法

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

如果没有指定Looper,会使用当前线程的Looper,如果当前线程没有looper,则报错。

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

指定Looper。常见的使用是,先创建HandlerThread实例,并start,然后再创建Handler,使用HandlerThread实例的Looper,比如在IntentService中。

Handler的sendMessage(),sendMessageDelayed()等方法最终都会调用到sendMessageAtTime,再调用enqueueMessage

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

对消息处理的回调,会调用Handler的dispatchMessage()。

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

Message

Message是Handler向MessageQueue发送的消息信息通过该类封装。

重要字段

int what: 用户定义的message code,消息接收者通过该code确定是哪一个消息。

int arg1,arg2:当发送的数据只是简单的1-2个int时,就用这两个变量,而不用setData(),是setData()的low-cost的替代方案。

Object obj:  发给接受者的一个任意对象。

如果要传递更多的数据,就用setData(Bundle bundle)。

获取Message实例的更好的方法是Message.obtain()

    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会从Message Pool中获取已经不再使用的Message,不需要再重新创建Message的实例。

    /**
     * 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;
    }
或者使用Handler的obtainMessage,其也是调用Message的obtain方法。

    /**
     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
     *  If you don't want that facility, just call Message.obtain() instead.
     */
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

    /**
     * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
     * 
     * @param what Value to assign to the returned Message.what field.
     * @return A Message from the global message pool.
     */
    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }


下面看下Message是如何维护Message Pool的。

    // 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;

    /**
     * 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++;
            }
        }
    }


    /*package*/ void clearForRecycle() {
        flags = 0;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        when = 0;
        target = null;
        callback = null;
        data = null;
    }


    /**
     * 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调用它的recycle()方法,比如在Looper.loop()中,clearForRecycle()将所有变量置空,sPool将值赋给当前Message对象的next,当前Message对象赋值给sPool,当下一个Message对象m2调用recycle时,m2的next指向之前sPool的值,即上一个Message对象,将m2赋值给sPool。

调用obtain时,如果sPool不为空,则有回收的Message,返回该Message,将该Message的next,即之前的Message赋值给sPool。

Message的类变量sPool,总是指向回收的Message链表的头元素,它相当于一个头指针。

总结

  1. 在Thread的run()中调用Looper.prepare()给Thread创建looper,调用Looper.loop()使Thread监听MessageQueue,准备处理消息;
  2. 创建Handler时默认的Looper是当前线程的Looper,也可以指定Looper,sendMessage()即向Looper所持有的MessageQueue发送消息,Thread从MessageQueue取得Handler发来的消息后,回调Handler的callBack或者handleMessage();
  3. 当处理完一条Message,调用Message的recycle(),放到Message Pool中备用;
  4. 当调用Looper的quit,会调用到MessageQueue的quit(),之后Thread的run方法执行完毕。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值