美文网首页
Handler源码 二

Handler源码 二

作者: 王灵 | 来源:发表于2019-02-20 18:56 被阅读0次

往下说之前先来统一一个前提:

  • 每个Looper和MessageQueue是唯一对于关系,而handler可以有多个
  • 每个线程只能有一个Looper

这篇主要围绕几个功能的实现来写。(虽然分为几个问题,但是问题不是独立的,后面的问题解答需要用到前面问题的内容)

1. Looper的线程唯一是如何实现的?

打开Looper代码有一个我们需要注意的属性
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal是静态常量。有两个我们需要知道的函数(使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。不知道它的用途可以百度)

sThreadLocal.set(looper);

保存looper,ThreadLocal内部会把当前线程和looper绑定。(类似map,key=线程 value=looper)

sThreadLocal.get()

获取当前线程的looper

2.在activity中我们使用Handler更新UI,只是新建了Handler对象,Looper和MessageQueue是在哪里初始化的?(不知道sThreadLocal是什么看问题1)

看handler的构造方法

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

如上mLooper是通过Looper的静态方法myLooper()获得,

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

???get()??? 实际上使用handler的第一步是调用Looper.prepare()

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

可以看到mLooper在prepare(boolean quitAllowed)里被创建,并设置到sThreadLocal。然后就可以通过sThreadLocal.get()获得到

查看Looper(quitAllowed)构造函数,可以看的MessageQueue在这里被创建

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

所以在调用Looper.prepare()时Looper和MessageQueue被new

3. 我们在Activity使用Handler更新UI时需要创建Handler就可以,而在子线程使用Looper时则需要调用Looper.prepare(),为什么?

实际上主线程的Looper已经被自动初始化好了,在HandlerThread的run函数,而且顺着调用了Looper.loop();

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

相关文章

网友评论

      本文标题:Handler源码 二

      本文链接:https://www.haomeiwen.com/subject/kinhyqtx.html