欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android 之 Handler ,Looper机制详解

程序员文章站 2022-03-01 13:09:20
...

Android 之 Handler ,Looper机制详解

Handler 在日常开发中异步操作时经常使用到,接下来我们就来分析Handler机制,主要分为两大部分:

  • 常见用法
  • 源码解读

常见用法

一般我们会在Acticity或者其他地方中new一个Handler ,并重写handleMessage的方法,在handleMessage中接受传过来的消息:

    private Handler mHandler = getLocalHandler();
    private final static int FIRST_MESSAGE = 1;
    private final static int SECOND_MESSAGE = 2;

    public Handler getLocalHandler() {
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case FIRST_MESSAGE:
                        //doFirstThing();
                        break;
                    case SECOND_MESSAGE:
                        //doSecondThing();
                        break;
                    default:
                        break;
                }
            }
        };
        return handler;
    }

然后可以在 其他的线程 或者 主线程 发消息给Handler,比如异步网络加载完数据之后:

    private void sendMessageToFirst() {
        Message msg = new Message();
        msg.obj = null;
        //可用 msg.what 来区别并执行不同的事项
        msg.what = FIRST_MESSAGE;
        mHandler.sendEmptyMessage(FIRST_MESSAGE);
    }

在 异步线程 或 主线程 我们也可以利用Handler来做延时处理操作:

    private void sendMessageDelayed() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                doSecondThing();
            }
        },2333);
    }

上诉就是我们比较常规的用法。

源码解读篇

接下来我们来分析下Handler,Looper机制的java源码

Handler(初始化):

首先看下new时Handler的构造器,代码如下:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback, boolean async) {
        //...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException("");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到,new时初始化 mLooper (Looper) ,mQueue (MessageQueue) ,mCallback (Callback) ,mAsynchronous (Boolean) 这四个对象。
下面我们逐一来分析他们:

Callback :

先说Callback,Callback是Handler类中的接口,其中的handleMessage与我们上述Handler重写的handleMessage是一样的方法名:

    public interface Callback {
        public boolean handleMessage(Message msg);
    }

我们直接看他调用的地方,它在dispatchMessage方法中被使用,dispatchMessage(Message msg) 是处理消息的分发的方法,而方法中的 handleMessage(msg) ,它是我们执行 handler中 sendMessage,post(Runnable)等方法的执行语句

    // dispatchMessage方法中被使用,dispatchMessage(Message msg) 
    // 是处理消息的分发的方法

    public void dispatchMessage(Message msg) {
        //..
        // 这个为callback
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //执行handler中 sendMessage,post等方法的分发执行语句
        handleMessage(msg);
    }

再看下callback调用的地方,可看到当 mCallback != null 且 mCallback.handleMessage(msg) 为 true 的时候 return 方法不继续往下走。不然执行handleMessage(msg),这说明我们在 handler 事件执行前多执行一些操作 或者 截断handler事件的执行,所以可以使用下述的初始化Handler构造器,不过很少使用到这个。

 //Handler.class

 public Handler(Callback callback) {
    this(callback, false);
 }

 Handler handler = new Handler(new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
           //可以在事件发送前自定义处理
           // doSomeThing();
           return false;
      }
  });

Looper:

接下来我们看下 mLooper 参数,它被赋值了 Looper.myLooper(),我们进Looper进去看,相关代码贴下去:

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

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

可以看到是从 sThreadLocal 获取一个Looper,使得且一个线程只有一个Looper,大家可以去网上搜索ThreadLocal的知识理解为什么线程只有一个Looper。在 get 之前肯定需初始化,我们找到初始化的地方,代码如下:

    private static Looper sMainLooper

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                    throw new IllegalStateException("");
            }
            sMainLooper = myLooper();
        }
    }

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

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

在代码中,我们可以看到新建了一个MessageQueue,我们进去看下:

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

    void quit(boolean safe) {
        if (!mQuitAllowed) {
                throw new IllegalStateException(
                "Main thread not allowed to quit.");
        }
        // ...
    }

其中quitAllowed代表这个消息队列是否可以停止,上诉可以看到赋值为false时,调用quit()方法会报异常, 而mPtr是被底层c++使用,这个我们先不理。此时初始化已经分析完毕。

Handler机制(启动):

在我们程序启动时,系统会调用 prepareMainLooper() 方法,并初始化主线程的 Looper ,使主线程有可以使用的 Looper(),其中prepareMainLooper() 中 prepare(false) 会使Looper运行起来且不允许MessageQueue消息队列中断,这也可以理解不然在主UI中中断了可就不好了,代码如下:

    // ActivityThread.class 主程序的入口

    public static void main(String[] args) {
        // ..
        Looper.prepareMainLooper();
        // ..
        Looper.loop();
        // ..
    }

在上面可以看到在主程序开始时就就调用了prepareMainLooper()并使Looper loop()了起来,我们看下loop()方法,代码如下 :

 public static void loop() {
        final Looper me = myLooper();
        // ...
        final MessageQueue queue = me.mQueue;
        // ...
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) { 
                return;
            }
            // ...
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                // ...
            }
            // ...
            msg.recycleUnchecked();
        }
    }

可以看到方法中,获取当前MessageQueue对象,并开启了死循环,当queue.next()消息队列没有消息就return继续等待,有消息的话就往下执行 msg.target.dispatchMessage(msg) 语句。我们去先下queue.next()中的内容,代码如下:

    // MessageQueue.class

    Message next() {
        // 当loop被停止或者弃用 ptr 为0
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        //...

        // 下一次消息触发时间
        int nextPollTimeoutMillis = 0;

        for (;;) { 
            //...
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 如果同步时执行 且 msg.target == null执行
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (
                    msg != null && !msg.isAsynchronous());
                }

                if (msg != null) {
                    if (now < msg.when) {
                        nextPollTimeoutMillis 
                        = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    nextPollTimeoutMillis = -1;
                }
                if (mQuitting) {
                    dispose();
                    return null;
                }
            }
            //...
        }
    }

我们可以看到通过next()方法,我们可以获取消息继而执行,接着target是什么,代码如下:

    // Message.class

    Handler target;

可以看到 target 是个Handler对象,之前有稍微讲下Handler的dispatchMessage()方法,让我们再看一遍详细代码:

    // Handler.class

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

    private static void handleCallback(Message message) {
        message.callback.run();
    }

    public void handleMessage(Message msg) {
    }

可以看到当传下来的消息msg中的callback不为空的时候,直接执行run()方法,不然就判断mCallback 是否为空且mCallback.handleMessage(msg)是否为true,不然就执行我们重写的handleMessage()方法。
那么target又是哪里赋值的呢,我们先看Message的构造器,代码如下:

    // Message.class
    public Message() {
    }

发现并没有赋值target的值,我们回想一般在新建Message消息后我们会发送出来,我们去那个方法看下:

    // Handler.class
    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendMessageDelayed(Message msg,
                             long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(
        msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(Message msg, 
                                     long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

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

到最后我们可以发现target = this为我们当前的Handler,最后我们看下enqueueMessage方法,代码如下:

    // MessageQueue.class
    boolean enqueueMessage(Message msg, long when) {
        //...
        synchronized (this) {
            if (mQuitting) {
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;

            // mMessages可以理解为上一次Message
            // 当mMessages不为空,或者启动时间为0的,或者启动时间小于mMessages的启动时间
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                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;
                prev.next = msg;
            }

            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

上述代码就是Message插入队列的代码。

总结:

Handler机制其实在Android机制中算比较好理解的,我们可以看到主要涉及的类有Handler,Looper,MessageQueue和Message。
在主线程中,
Handler:负责对外,比如消息的添加,移除等功能,
Looper:个人理解作为一个载体,承载着消息队列的启动,获取及销毁消息,使Handler不必对MessageQueue进行管理,专注处理对外事件的处理
MessageQueue:对消息的循环移除,及对C++代码的通信。其中涉及到部分的jni代码本篇暂时还没解析,有兴趣的同学可以自行了解或谷歌。
这也是本人的第一篇博客,如果有什么写的错误或者不足的,请大家留言帮忙纠错!0-0