Android Looper、Handler与Message邂逅

  • 前言

    太久没更新会让大家觉得我是个很懒的人, 这也一直困扰着我, 学不到东西,以后怎么找工作啊, 不说了,很快就要找实习了,赶紧备些干货.


  • Looper

    每个线程都只可以有一个Looper

    Looper无非就是先Looper.prepare(),再Looper.loop()

    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();
    }
    
    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;
    
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
    
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }
    
            ...
            ...
    
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
    
            ...
    
            msg.recycleUnchecked();
        }
    }

    上面代码省略了一些打印的代码, 大家可以清晰地看到

    1. prepare()里会new 一个Looper, 但是会先判断如果已存在Looper就抛出异常

    2. Looper的构造方法, 创建MessageQueue和绑定当前的线程

    3. loop方法, 最主要还是for无限循环里,每次读取一条消息,然后交给msg.target.dispatMessage方法.再回收每条消息的资源

    Looper的主要作用就是

    1. 绑定当前线程,同时一个Looper也只有一个MessageQueue

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

  • Handler

    Handler是如何与MessageQueue联系的, 而又是如何在子线程发送消息到MessageQueue的.

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

    可以从倒数的第8和第3行看出来, Handler就这样跟MessageQueue联系上了

    下面我们看看经常使用的sendMessage方法

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
    
    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) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    最终的调用是sendMessageAtTime(…), 而刚刚好,这里有MessageQueue, 我们就很清楚地看到Handler与MessageQueue的互动

    继续看enqueueMessage()方法

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

    之前我们Looper里有写到msg.target, 这里的target在上面赋值为这个handler, 然后调用MessageQueue的enqueueMessage方法将msg插入到消息队列中

    现在我们更加清楚了,接下来继续看明白dispatchMessage方法

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

    这里出现了callback, 首先我们理清一下逻辑

    1. 如果msg.callback不为null, 就直接调用handler.handleCallback(msg)

    2. 如果msg.callback为null, 那么继续如果mCallback不为null, 并且如果mCallback成功处理消息,那么return, 否则, 调用handler.handleMessage(msg)

    看看什么是handleMessage

    public void handleMessage(Message msg) {
    }

    源代码是空的, 为什么呢, 不知道大家还记不记得, 经常使用Handler的时候,都会重写handleMessage方法然后根据msg.what来进行操作

  • 总结

    • Looper.prepare方法初始化Looper,创建MessageQueue消息队列,然后使用loop方法想MessageQueue无限读取消息,回调msg.target.dispatchMessage方法
    • Handler的初始化, 绑定当前线程的Looper和MessageQueue, 重写handleMessage方法, 根据msg.what进行相应的UI更新
  • 为什么使用时没有看到Looper.prepare方法

    那是因为Activity启动的时候就已经在当前UI线程调用了Looper.prepare()方法和Looper.loop()方法了

  • 相关知识

    • MessageQueue

      虽然叫做’消息队列’,其实是一个单链表

      前面讲到msg会通过queue.嗯queueMessage()方法插入队列中, 同理还有取得下个消息的方法next(), 这里就不一一贴代码了

      主要是想讲一下, 如果队列没有消息或者有延迟的消息, 这里就会阻塞.然后会回调监听阻塞的观察者

    • Looper如何停止

      有两种方法, Looper.quit(), Looper.quitSafely(), 同种都是调用MessageQueue.quit(boolean)方法

      1. quit() :立即回收所有消息, 这个是不安全的, 一般使用quitSafely()

      2. quitSafely() : 回收没执行的消息

  • 参考资料

    Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值