消息响应,Handler、Looper、Message关系

在使用线程创建Handler进行消息处理时,会使用如:

new Thread(){
            @Override
            public void run() {
                Looper.prepare();
                handlerthread = new myHandler() {
                    @Override
                    public void handleMessage(Message msg) {
                        System.out.println("thread handle : "+msg.obj);
                        ...
                    }
                };
                Looper.loop();
            }
        }.start();

使用

Looper.prepare();

  处理handleMessage业务逻辑

Looper.loop();

的方式来处理数据、更新UI。

而为什么可以在线程处理Handler数据Looper又是干什么的,在整个消息处理的流程是怎么样的?接下来我们来分析一下。

1.初始化

Looper.prepare()

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

分析ThreadLocal类在这篇文章中,介绍了ThreadLocal类的作用,这里不细说,简单就是存放了一个Looper对象,在该线程的某个时刻取出来使用。所以,一个线程只有一个Looper实例

我们来看看new Looper()做的事情。

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

在这里,Looper的实例创建了MessageQueue对象,保存了当前的线程。

Looper.loop()

public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            final long end;
            try {
                msg.target.dispatchMessage(msg);
            } finally {
            }
            msg.recycleUnchecked();
        }
    }

这里保留核心的逻辑。看一下myLooper(),就是获得前面prepare()方法里新创建的Looper对象。

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

再获取Looper里面的MessageQueue。接着for循环处理消息队列里面的消息。其中源码注释了might block没消息时会进行阻塞(涉及到Linux pipe/epoll机制,不细讲)。

处理数据能猜到,就是msg.target.dispatchMessage(msg)方法。

msg.target为Handler类型,所以实际是调用Handler.dispatchMessage方法

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

这里能看到,handleMessage就是我们一开始例子里面我们重写的Handler方法,就是我们要实现的业务逻辑。

到这一步我们可以整理一下Handler、Looper、Message的关系,如下图:

2.发送消息

那我们是怎么样把Message插入到MessageQueue里面呢?我们来看一下调用流程:

通常我们都是调用Handler实例.sendMessage() 、sendEmptyMessage() 、post()等方法,

实际都是调用MessageQueue.enqueueMessage()方法,源码如下:

boolean enqueueMessage(Message msg, long when) {

        synchronized (this) {
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

for循环可以看出,找到消息队列的最后一个,把要处理的消息插入到队列最后。

我们来整理一下整个执行的流程。

1.初始化:

Looper.prepare();

调用sThreadLocal.set(new Looper(quitAllowed))方法。实例化Looper类,保存在线程的ThreadLocalMap中。

Looper.loop();

Looper me = myLooper(); 获取Looper.prepare()方法生成的Looper。

for循环,遍历MessageQueue,等待消息插入队列,无消息时可能会被挂起。

2.发送消息:

Handler.post()、Handler.sendMessage()、Handler.sendEmptyMessage()

最后调用函数enqueueMessage(queue, msg, uptimeMillis),添加msg到MessageQueue

3.执行消息:

msg.target.dispatchMessage(msg);

handleMessage(msg);执行自己添加的业务逻辑

最后,我们来看一开始提出的问题:

为什么可以在线程处理Handler数据?

因为在Looper初始化时,已经绑定了当前调用的线程,只要往消息队列放数据,在loop()方法的循环都能处理。

Looper又是干什么的?

从前面对应关系图可以看到,作用有

1.存放MessageQueue

2.绑定当前调用线程

3.Loop()方法负责循环处理消息

在整个消息处理的流程是怎么样的?

处理流程按照前面所讲的,Looper初始化后,发送消息时放入消息队列,在loop()方法取出处理。

这里再扩展一个问题,为什么在主线程调用的Handler实例不需要Looper呢?

因为Android程序入口点Android.app.ActivityThread的main()方法里,也调用了Looper.prepareMainLooper和Looper.loop()。

猜你喜欢

转载自blog.csdn.net/weixin_40972376/article/details/81281102
今日推荐