Handler,Looper,MessageQueue,android中的消息机制以及源码分析(二)

本篇主要是简单介绍消息机制模型和各组件的了解,源码分析请见Handler,Looper,MessageQueue,android中的线程通信以及源码分析(一)


让我们从handler默认构造函数开始入手。默认的构造函数中实际调用的构造函数,如下图:

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


        <strong>mLooper = Looper.myLooper();</strong>
        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;
    }

mLooper是handler中一个私有成员Looper,至于Looper是什么欢迎看上一篇博文~我们先接着往下看,在这里调用了Looper的静态方法myLooper()

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }


sThreadLocal是Looper中的一个final的静态成员ThreadLocal,如下图:

<span style="font-size:14px;"> // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();</span>


下面我简单先说一下什么是ThreadLocal。(有关Threadlocal细节

从字面上来看,线程本地变量。什么意思?就是针对每一个线程都会有一个变量的线程副本存在。不理解没关系,接着往下看。

在Thread线程中有一个成员变量Threadlocal.Values

     /**
     * Normal thread local values.
     */
    ThreadLocal.Values localValues;

可这又是什么呢?

在Threadlocal.Values当中的私有成员table,用来存放变量副本。

        /**
         * Map entries. Contains alternating keys (ThreadLocal) and values.
         * The length is always a power of 2.
         */
        private Object[] table;


说白了,ThreadLocal就是针对每一个线程都维护了一个Values对象,Values中的table是真正存放变量副本的一张表。

这个问题现在理解起来可能比较困难,我们先放一放,接着看下面的内容。

Looper在初始化的时候都会调用它的静态方法prepare,并且在new Looper的同时完成了消息队列的初始化。

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        <strong>sThreadLocal.set(new Looper(quitAllowed));</strong>
    }
private Looper(boolean quitAllowed) {
        <strong>mQueue = new MessageQueue(quitAllowed);</strong>
        mThread = Thread.currentThread();
    }

在prepare里面可以看见,首先调用threadlocal的get方法,这个方法做了什么事情呢?是把该线程中所保存的线程副本Looper对象取出来,如果该对象已存在,根据一个线程中只能有一个Looper,会报出异常,否则new一个新的Looper对象并放入线程副本中。


那么接下来,我来解释一下什么是线程副本。

之前有说过每一个线程中都维护了一个Looper,可是每一个线程中的Looper又互不干扰,各司其职。在这样的情况下,通过ThreadLocal来对每一个线程维护一个Looper实例,各自不互相干扰。如果是所有的线程都共用一个Looper的话,首先资源开销会很大,而且由于队列可能会很长,消息分发会不及时等等。还有可能会因为并发带来阻塞等问题。而采取在每一个有需要使用Looper的线程中,用ThreadLoca对这一Looper维护,更有效的利用了资源,效率也会更高。这就是线程副本的作用。


正常在使用handler消息机制时应该是例如下面的写法:

        new Thread(new Runnable() {
            @Override
            public void run() {

                <strong>Looper.prepare();</strong>
                Log.i("XXX", "创建handler");

               <strong>handler = new Handler()</strong> {

                };

                <strong>Looper.loop();</strong>
 
            }
        }).start();

首先Looper.prepare()在线程中创建Looper实例和消息队列。然后实例化handler并完成对当前线程looper和队列的绑定。所以我们可以看到,handler执行的线程是looper所处的线程。而默认构造函数的handler默认是和当前所在线程绑定的。当然我们也可以通过如下构造,为handler指定looper,即绑定了looper所在的线程。

 public Handler(<span style="color:#ff6666;">Looper looper</span>, Callback callback, boolean async) {
        <strong>mLooper = looper</strong>;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
最后是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();

       <strong>for (;;)</strong> {
            M<strong>essage msg = queue.next();</strong> // 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);
            }

            <strong>msg.target.dispatchMessage</strong>(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.recycleUnchecked();
        }
    }

我们可以看红色的代码部分。首先loop()里面存在一个死循环,那么在死循环中做了哪些事情?
Message msg = queue.next(); // might block
取出消息队列中的下一个Message,如果消息队列中没有消息则会一直阻塞,直到有消息位置才会返回消息。如果返回的是一个null值时,说明消息对流已经关闭,对应的Looper也应该关闭,return掉。
 msg.target.dispatchMessage(msg);
在这一行代码中,Message对象持有一个handler的引用target,即调用Message对应的handler的dispatch方法将消息分发出去。

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

在dispatch中设计到一个优先级的问题。

优先执行massage中实现的callback

    private static void handleCallback(Message message) {
        message.callback.run();
    }
其次是handler中实现的Callback接口

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

最后才是官方例子中所示,也是我们最常用的handleMessage方法

    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }



说完了怎么去分发执行消息,下面我们来看看消息是如何被添加到消息队列中的。


首先相信大家都知道,更新UI的几种方式:

·      Activity.runOnUiThread(Runnable)

·      View.post(Runnable)

·      View.postDelayed(Runnable, long)

·      Handler

这几种方式其实都是采用的handler中的post方法,而后调用sendMessageAtTime方法。

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     * 
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *         
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    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 <strong>enqueueMessage(queue, msg, uptimeMillis)</strong>;
    }

enqueueMessage方法是将message加入队列的方法,如下:

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

调用了消息队列中的加入队列方法。



队列中的Message又是怎么存取的呢?

Message中有一个指向下一个Message的引用next。那么我们不难理解,Message使用了最简单的链式结构,而并没有使用像是并发处理中的竞争队列之类的结构。Message的存取是一个FIFO(先进先出。。虽然我这句是废话。。。。大家一定都知道)队列。

    // sometimes we store linked lists of these things
    /*package*/ Message next;

Message实现了Parceble,用于消息传递

public final class Message implements Parcelable

 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];
        }
    };

android线程模型是一个单线程模型,即只有UI线程负责更新UI。因为虽然cpu可能会有多个,但是显示只有一个。

为了遵从单线程模型,费时操作必须在子线程中实现。这样的话就涉及到子线程和主线程之间的通信,由此引入了消息机制。


还有就是可能会有人说以前没有用过prepare和loop也可以直接使用handler。那是因为在主线程中,默认有主线程looper,在主线程启动时就已经prepare并且loop了,自然就不用我们自己去实现~


下面这段代码就是ActivityThread中的主函数:

 public static void main(String[] args) {
            SamplingProfilerIntegration.start();

            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);

            Environment.initForCurrentUser();

            // Set the reporter for event logging in libcore
            EventLogger.setReporter(new EventLoggingReporter());

            Process.setArgV0("<pre-initialized>");

            <strong>Looper.prepareMainLooper();</strong>

            // 创建ActivityThread实例
            ActivityThread thread = new ActivityThread();
            thread.attach(false);

            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }

            AsyncTask.init();

            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }

            <strong>Looper.loop();</strong>

            throw new RuntimeException("Main thread loop unexpectedly exited");
        }


----------割割割-------------


在这里其实我自己是有一个疑问的,主线程中loop()后会一直阻塞,那么android就是不停的loop,实现消息传递的结果么?还希望有人可以指导一下~~~么么哒(づ ̄ 3 ̄)づ


自问自答好了。。

http://stackoverflow.com/questions/6984263/android-looper-and-call-stack

everything that happens on the UI thread is through that loop

这样看来。。确实android的显示就是一个loop的死循环




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值