【Android】 子线程中可以new Handler么?为什么?

937 阅读2分钟

能不能 new Handler?

这里需要从源码出发,在任意java文件中new Handler(),跟进查看Handler源码的具体实现。

 public Handler(@Nullable 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();
        //注释 1
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

异常信息: that has not called Looper.prepare() 提示我们需要添加Looper.prepare()

注释1:从上面代码可以看出,如果说mLooper 为空的话,这段代码会直接抛出异常,我们可以理解为不能直接new Handler()。那mLooper到底是不是为空呢,这里继续查看Looper.myLooper();

    public static @Nullable Looper myLooper() {
        //注释 2 
        return sThreadLocal.get();
    }

注释2 : 从这段代码可以看出,Looper是从sThreadLocal中直接取出的,如果对ThreadLocal实现原理有了解,那么很容易就可以看出,如果直接没有存储Looper,这里获取到的肯定为空,那么上面一段代码执行肯定会抛异常;

从上面源码跟踪可以得出结论:如果在子线程没有在ThreadLocal中存储当前线程的Looper,那么Handler是不能被new的。

这里还可以引申看看为什么主线程是可以new Handler的 ,同样查看源码: 查看ActivityThread.java 的main()方法中可以看到如下代码:

 public static void main(String[] args) {
    ... ...
        //注释3
        Looper.prepareMainLooper();

    ... ...
    }

注释3:这里可以看到在main方法中调用了Looper.prepareMainLooper(),继续跟踪进入

    public static void prepareMainLooper() {
        //注释4
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

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

注释4:这里调用的是prepare()方法,在prepare()中我们可以看到sThreadLocal.set(new Looper(quitAllowed)); 所以这就是主线程可以直接new Handler的原因。

所以,如果我们在子线程中也调用Loop.prepare()也可以使用new Handler()的。(当然这一点可以从一开始抛出的异常中可以看出。同时需要注意Looper.loop()的使用哦)

回到题目,子线程可以new Handler么,为什么?