Handler looper message详解

来源:互联网 发布:js隐藏元素 hidden 编辑:程序博客网 时间:2024/06/01 09:07

1.handler在主线程中使用

new Handler().post(new Runnable() {        @Override        public void run() {              //操作        }    });

可以看到,new了Runnable像是开启了一个子线程,但是不然,大家可以看到这儿调用的是run方法,而不是start方法,因此并不是子线程,其实还是在主线程中。


2.handler在子线程中使用


new Thread(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1000);                    Handler handler = new Handler();                    handler.post(new Runnable() {                        @Override                        public void run() {                            mTest.setText("post");//更新UI                        }                    });                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }).start();

3.looper源码解析

sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。可以看到,将一个Looper的实例放入了ThreadLocal,并且判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例

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

在looper构造方法中,创建了一个MessageQueue(消息队列)。

    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }


    /**     * 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            final Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            final long traceTag = me.mTraceTag;            if (traceTag != 0) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            try {                msg.target.dispatchMessage(msg);            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            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();        }    }



Looper主要作用:

1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。

2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。


4.handler源码解析

通过Looper.myLooper()获取了当前线程保存的Looper实例,然后又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。

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

0 0