Loop、Handler、MessageQueue和Message源码分析

Handler

先看Handler构造函数

// 默认构造函数,内部调用了带有两个参数的构造函数
public Handler() {
    this(null, false);
}

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

主要做了这几方面的工作:
1. 获取创建Handler的线程的Looper对象
2. 将消息队列和回调等保存在Handler的变量中,用于后续的消息处理

这里我们可以注意到,假如获取的Looper对象为空,就会抛出异常:throw new RuntimeException(“Can’t create handler inside thread that has not called Looper.prepare()”);这个异常很常见,特别是在子线程中创建Handler时(具体原因,接下来分析)

我们可以先看下是如何获取Looper对象的

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static Looper myLooper() {
    return sThreadLocal.get();
}

可以看到其内部调用了sThreadLocal.get()方法,那sThreadLocal是什么?

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

是Looper内部的一个静态final变量,源码中有解析:需要先调用Looper.prepare()方法,否则sThreadLocal.get()会返回空。可见,是在prepare()方法中对sThreadLocal进行了赋值,进入到prepare()中

/** Initialize the current thread as a looper.
  * This gives you a chance to create handlers that then reference
  * this looper, before actually starting the loop. Be sure to call
  * {@link #loop()} after calling this method, and end it by calling
  * {@link #quit()}.
  */
public static void prepare() {
    prepare(true);
}

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

这段说明和代码给我们三点提示:
1. prepare()只能调用一次,用于为调用线程创建一个Looper对象
2. sThreadLocal为每一个调用线程保存了一个Looper对象,美俄个Looper对象互不干扰
3. 使用loop()方法开始轮询,使用quit()方法结束轮询

那为什么我们在主线程直接创建Handler不会发生异常呢?这是因为主线程在启动时,已经为我们调用了prepare()这个方法,进入ActivityThread的main()方法中查看

public static void main(String[] args) {
    ......
    ......
    // 省略部分代码

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Looper.loop();

    ......
    ......
    // 省略部分代码
}

可以看到调用调用了Looper的两个主要方法:
1. Looper.prepareMainLooper();

获取主线程的Looper对象,内部调用了prepare()方法
2. Looper.loop();
开始轮询

Looper

先看Looper的构造函数

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

构造函数是私有的,所以在外部使用不能直接创建Looper对象,必须通过调用Looper.prepare()方法生成

这里主要完成两个任务:
1. 创建与该线程绑定的MessageQueue对象
2. 获取当前线程,并保存在Looper中

调用prepare()后,需要调用loop()函数开始轮询,接下来分析loop()函数

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the 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();
    }
}

几点分析:
1. 使用了一个for (;;) 无限循环来轮询MessageQueue中的消息
2. Message msg = queue.next(); // might block

获取消息队列中的下一条消息,这个方法可能会阻塞
3. 假如获取到下一条消息,调用msg.target.dispatchMessage(msg);来分发消息
target类型为Handler,每一条Message中保存了一个Handler类型的target字段,用于区分不同Handler发送的消息

除了上边的分析的几个函数,Looper还提供了另外几个常用的函数:

// 获取主线程的Looper对象
public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

// 获取与Looper对象关联的Thread
public Thread getThread() {
    return mThread;
}

// 获取与当前Thread关联的MessageQueue对象
public static MessageQueue myQueue() {
    return myLooper().mQueue;
}

dispatchMessage分析

从上边可以看到,在loop()中通过调用handler.dispatchMessage(msg);来派发消息;那消息是如何被接收和被处理的呢?我们进入dispatchMessage查看

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

这里边处理了三种情况:
1. msg.callback(为Runnale接口)不为空,直接调用msg.callback.run()

private static void handleCallback(Message message) {
    message.callback.run();
}
  1. 假如Callback类型变量mCallback不为空,则调用mCallback.handleMessage
// Callback为Handler内部定义的接口,可通过Handler的构造函数传递进来
public interface Callback {
    public boolean handleMessage(Message msg);
}
  1. 假如上边两种都为空,则直接调用handleMessage

public void handleMessage(Message msg) {
}

可看到handleMessage为空函数,我们在使用handler时,需要处理信息,就可以重写该方法,进行需要的处理

MessageQueue

主要分析它的next()函数

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (false) Log.v("MessageQueue", "Returning message: " + msg);
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

其内部也是使用一个for (;;)无限循环来获取下一个Message

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值