Android Looper、Handler与Message邂逅

来源:互联网 发布:p2p网贷软件系统 编辑:程序博客网 时间:2024/05/20 12:24
  • 前言

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


  • 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三者关系

原创粉丝点击