zoukankan      html  css  js  c++  java
  • Android源码分析之Handler

      接上一篇分析,正如Android doc所说,Handler主要有2方面用处:

    1. delay执行同一线程中的某个操作,也就是schedule message、runnable在未来的某一时刻执行;

    2. 给另外一个线程发送message、runnable,让某个操作在另一个线程中执行。比如A线程只要能拿到B线程的

    handler就能通过此handler在A线程中通过post message、runnable,让这些消息的处理发生在B线程中,从而实现

    线程间的通信。AsyncTask就是通过在background线程中通过关联UI线程的handler来向UI线程发送消息的。为了看的

    更清楚些,这里摘抄下Looper.java开头处给的一个典型例子:

      * This is a typical example of the implementation of a Looper thread,
      * using the separation of {@link #prepare} and {@link #loop} to create an
      * initial Handler to communicate with the Looper.
      *
      * <pre>
      *  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();
      *      }
      *  }</pre>

    在这里,别的线程可以通过LooperThread.mHandler来实现和它的通信。

      接下来一点点分析源码,先看几个相关的:

    /**
         * Callback interface you can use when instantiating a Handler to avoid
         * having to implement your own subclass of Handler.
         *
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
        
        /**
         * Subclasses must implement this to receive messages.
         */
        public void handleMessage(Message msg) {
        }
        
        /**
         * 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);
            }
        }

    这个Callback接口里只有一个handleMessage方法返回boolean值,在后面Handler的ctor会用到,一般情况下都是null。这个接口的存在

    没什么特殊的含义,只是为了让你不extends Handler就能处理消息而已(正如此方法的doc所说),类似Thread和Runnable接口的关系。

    接下来是dispatchMessage方法,我们已经在上一篇分析Message的时候大概提到了。它的处理是如果message自身设置了callback,则

    直接调用callback.run()方法,否则Callback接口的作用就显现了;如果我们传递了Callback接口的实现,即mCallback非空,则调用它处理

    message,如果处理了(consumed)则直接返回,否则接着调用Handler自己的handleMessage方法,其默认实现是do nothing,如果你

    是extends Handler,那么你应该在你的子类中为handleMessage提供自己的实现。

      接下来我们首先看看Handler都有哪些关键的字段,源码如下:

    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    final boolean mAsynchronous;

    mQueue来自mLooper,mLooper要么是在ctor中显式指定的要么是默认当前线程的,Handler关于Message、Runnable的所有处理都delegate给了mQueue;mCallback是用户提供的Callback实现,默认是null;mAsynchronous表示Handler是否是异步的,默认是同步的。

      接下来我们来看各种各样的Handler的ctor(构造器):

    /**
         * Default constructor associates this handler with the {@link Looper} for the
         * current thread.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         */
        public Handler() {
            this(null, false);
        }
    
        /**
         * Constructor associates this handler with the {@link Looper} for the
         * current thread and takes a callback interface in which you can handle
         * messages.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         *
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Callback callback) {
            this(callback, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one.
         *
         * @param looper The looper, must not be null.
         */
        public Handler(Looper looper) {
            this(looper, null, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one and take a callback
         * interface in which to handle messages.
         *
         * @param looper The looper, must not be null.
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }
    
        /**
         * Use the {@link Looper} for the current thread
         * and set whether the handler should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with represent to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        public Handler(boolean async) {
            this(null, async);
        }
    
        /**
         * Use the {@link Looper} for the current thread with the specified callback interface
         * and set whether the handler should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with represent to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param callback The callback interface in which to handle messages, or null.
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        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;
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one and take a callback
         * interface in which to handle messages.  Also set whether the handler
         * should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with represent to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param looper The looper, must not be null.
         * @param callback The callback interface in which to handle messages, or null.
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }

    我们来看3个参数的版本,即Looper,Callback,boolean,默认looper是关联的当前线程的,callback是null,async是false。当然你愿意也可以分别指定这3个值。关于ctor不需要赘述,看doc、comment就可以很容易理解。

      接下来是一堆Handler的obtainMessage函数,其实现都是直接调用Message的静态函数obtain,但相应的message的target字段都自动被设置成了当前的Handler对象。由于Message的源码已在上一篇中分析过了,这里一带而过。

      getPostMessage(Runnable r)之类的也很简单,就是将runnable包装成一个Message,其callback字段被设置成了runnable。

      接下来的一堆postxxx、sendxxx,最终会调用下面这个方法:

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

    在这里,message的target被设置成当前的Handler,如果是异步的Handler,则设置message也为异步的,然后入队,uptimeMillis表示绝对时间戳。这里需要提一下的是xxxAtFrontOfQueue方法,这个方法因为每次是将后来的message插在队列的前头,所以可能导致队列中的其他消息没机会得到处理(即饥饿),或得不到及时处理,所以说插队是不好的,慎用。正如其方法doc中所说,其实在我们的工作学习中,我也强烈推荐大家仔细看看相关类、方法的doc。我知道我们这类人都不喜欢写doc,所以既然能有doc那说明真的是必不可少的,挺重要的。

      接下来是removeCallbacks相关的,源码:

    /**
         * Remove any pending posts of Runnable r that are in the message queue.
         */
        public final void removeCallbacks(Runnable r)
        {
            mQueue.removeMessages(this, r, null);
        }
    
        /**
         * Remove any pending posts of Runnable <var>r</var> with Object
         * <var>token</var> that are in the message queue.  If <var>token</var> is null,
         * all callbacks will be removed.
         */
        public final void removeCallbacks(Runnable r, Object token)
        {
            mQueue.removeMessages(this, r, token);
        }

    其实现也都是delegate给了mQueue,有一点需要注意下就是这些方法会remove掉所有的Runnable r,而不是第一个匹配的

    (注意方法名中的s,是复数而不是单数),也就是说一次remove调用可以remove掉之前好多次post的同一个runnable,

    如果之前post的runnable还在队列中的话。

      removeMessages、hasMessages之类的方法挺简单不过多解释。

      Handler类的分析就到这了。。。(由于本人水平有限,欢迎批评指正

     
  • 相关阅读:
    用Python完成一个汇率转换器
    鸿蒙如何用JS开发智能手表App
    鸿蒙如何用JS开发智能手表App
    SAP Spartacus SplitViewComponent Migration 的一个具体例子
    SAP Spartacus B2B 页面 Popover Component 的条件显示逻辑
    SAP Spartacus 升级时关于 schematics 的更新
    SAP Spartacus B2B 页面 Disable 按钮的显示原理
    SAP Spartacus B2B 页面 Disable Confirmation 对话框的显示原理
    通过 Feature Level 动态控制 SAP Spartacus 的页面显示
    SAP Commerce Cloud Build Manifest Components
  • 原文地址:https://www.cnblogs.com/xiaoweiz/p/3660585.html
Copyright © 2011-2022 走看看