Android Looper源码剖析

作者: phantomvk | 来源:发表于2016-12-12 15:28 被阅读0次

    一、数据成员

    每个Looper拥有一个消息队列,归属于一个线程。

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // 由Looper.class控制
    
    final MessageQueue mQueue;
    final Thread mThread;
    

    二、初始化

    每个线程创建一个Looper,如果线程尝试创建第二个Looper就会出现异常。

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

    先创建一个消息队列和Looper所运行的线程。方法是私有的,只能由prepare()调用。

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

    Android环境会通过这个方法自动创建主线程Looper,千万不要在主线程中再次调用这个方法。

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

    三、启动Looper

    把这个线程Looper的queue里面的消息送去处理

    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(); // MessageQueue可能会阻塞
            if (msg == null) {
                // 消息队列关闭,Looper退出
                return;
            }
            // msg.handler.dispatchMessage(msg),消息发送到Handler回调
            msg.target.dispatchMessage(msg);
            // 确保消息在分发的时候线程没有改变
            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();
        }
    }
    

    四、消息队列退出

    消息队列关闭

    public void quit() {
        mQueue.quit(false);
    }
    
    public void quitSafely() {
        mQueue.quit(true);
    }
    

    五、一般方法

    返回Looper所属的线程和消息队列

    public @NonNull Thread getThread() {
        return mThread;
    }
    
    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }
    
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
    

    返回所属线程的Looper。如果子线程没有调用Looper.prepare(),sThreadLocal.get()为空。

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

    获取线程Looper的消息队列

    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }
    

    返回当前的线程是否就是Looper的线程

    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }
    

    相关文章

      网友评论

        本文标题:Android Looper源码剖析

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