『 面试题 』之 Android中的消息机制?

大尾巴狼

其实问这种问题,无非就是想知道你对handler了解怎么样。虽然handler这种问题已经被问烂了,但是很多公司,尤其是中小型企业,

被问的几率还是很高,所以,再次记录一下,也很简单,没事儿的时候点进源码看看就明白。

  • Android 的 多线程通讯核心类是Handler!

通常我们在使用多线程通讯的方式,是在 线程A(或UI线程) 中创建 handler,在线程B中 使用 handler的实例,调用其方法 例如:sendMessage(Message msg)sendEmptyMessage(int what),发送我们需要传送的数据放进了Messagequeue里面。然后被主线程或者是实例化化handler的线程 的Looper循环到,然后执行。

通过源码我们大致可以理出一条线路来:

图片描述

需要注意的是,ThreadLocal 该类是用于创建线程局部变量的类,我们知道,通常情况下一个变量是在多个线程中都能访问的,但是ThreadLocal,可创建一个只在当前线程访问的变量。他支持泛型,回到我们的面试题上

这里 我们可以逐步分析:

public Handler(Callback callback, boolean async) {
        
       //得到主线程(已经被ActivityThread初始化好)的looper
       mLooper = Looper.myLooper();
       if (mLooper == null) {
           throw new RuntimeException(
               "Can't create handler inside thread that has not called Looper.prepare()");
       }
       
       //得到主线程(已经被ActivityThread初始化好)的looper的MessageQueue,注释:①
       mQueue = mLooper.mQueue;
       mCallback = callback;
       mAsynchronous = async;
}

注意,看到了吗? 这里是核心:mLooper = Looper.myLooper();

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

而这个Looper对象,是在我们启动程序的时候,也就是ActivityThread 中的main方法帮我们初始化的,也就是我们主线程的Looper。

public static void prepareMainLooper() {
     ···
     prepare(false);
     ···
}

--------------------------------------------------

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

我们在子线程 使用 handler的实例进行 sendMessage(Message msg) 的时候:

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

最终走向enqueueMessage:

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

最终把我们的Message,放进了主线程的MessageQueue里面进行循环!

阅读 2k

间歇性雄心斗志,持续性混吃等死!

246 声望
3 粉丝
0 条评论

间歇性雄心斗志,持续性混吃等死!

246 声望
3 粉丝
文章目录
宣传栏