Android中Handler消息机制

在Android中我们通常所讲的消息机制所指的就是Handler消息处理机制或者说就是Handler的运行机制一提及Handler难免要跟Looper、MessageQueue产生联系,我是这么总结它们:Handler通过post、send方式把Message放入MessageQueue中,Looper会无限循环MessageQueue有数据就处理没数据的话就一直等待着。

首先,ThreadLocal的工作原理

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

在Looper中有这么一个变量,所以我们需要理解ThreadLocal是什么鬼。ThreadLocal是一个线程内部数据存储,当调用ThreadLocal.set()方法后我们只有在set线程中可以拿到数据别的线程无法ThreadLocal.get()得到数据。

ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<Boolean>();
        mThreadLocal.set(true);
        System.out.println("--Main == " + mThreadLocal.get());

        new Thread() {
            public void run() {
                mThreadLocal.set(false);
                System.out.println("--thread1 == " + mThreadLocal.get());
            };
        }.start();

        new Thread() {
            public void run() {
                System.out.println("--thread2 == " + mThreadLocal.get());
            };
        }.start();

我们声明一个ThreadLocal变量在主线程中set(true),在Thread1中set(false),在Thread2中没有任何处理。

--Main == true --thread1 == false --thread2 == null

从运行结果我们可以看出就算是同一个变量但是不同线程读取却是不同的值,这就是ThreadLocal的奇怪且奇妙的地方。

其次,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));
    }

往sThreadLocal中存如Looper对象。

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

在Looper中mQueue = new MessageQueue(quitAllowed)使得Looper跟MessageQueue挂上勾,所以说每一个Looper内部都有一个MessageQueue来存放Message。

最后,Handler工作流程
Handler可以post、send消息可是最终都是调用

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

将当前传入的Message加入消息队列中去。这个时候Looper.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.recycleUnchecked();
        }
    }

Message msg = queue.next()这句代码会启到如果没数据loop就被阻塞住了,当msg不为null的时候msg.target.dispatchMessage(msg)会顺利走到这一步其中msg.target指的其实就是Handler对象所以会回跳到dispatchMessage方法

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

如果是handler.post…(new Runnable…)那么就会执行handleCallback方法回调到Runnable对象的run方法,所以这个Runnable其实不是一个线程只是一个回调类而已。
如果是handler.sendMessage…系列的话就会回调到handleMessage方法中去,所以常见我们会重写handleMessage这个放来接受消息。
如果我们是通过Handler(Callback callback)来初始化一个Hanlder的时候那么就会mCallback.handleMessage(msg)所以我们需要重写Callback的handleMessage来接收消息。

最后,如果初始化一个典型的Handler呢?

Looper.prepare();
                new Handler();
                Looper.loop();

可是如果在主线程中初始化的时候我们只需要new Handler()就好, 这是为什么呢,因为系统在启动的时候已经调用了Looper.prepare()和Looper.loop()。 这样经过初始化后 在哪个线程初始化该Handler对应就运行在哪个线程中,然后其中就是通过ThreadLocal来读取具体的线程下的Looper。

所以如何在一个线程中初始化一个主线程的Handler呢?

new Thread() {
            @Override
            public void run() {
                new Handler(Looper.getMainLooper());
            }
        };

Looper.getMainLooper()获取就是在app启动的时候主线程中Looper.prepareMainLooper初始化出来的Looper对象,通过传入该Looper那么这个Handler就是会把消息传入主线程。

综上,就是我自己对Handler消息机制的理解 。

你可能感兴趣的:(handler,消息机制)