Android消息队列初识 && ThreadLocl 简述

Android消息队列初识

ThreadLocal

Thread类内部的一个字段ThreadLocal.ThreadLocalMap字段存放着本线程共享的数据

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadlocalMap是ThreadLocal的一个静态内部类

    /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

        /**
         * The number of entries in the table.
         */
        private int size = 0;

可以看出ThreadLocalMap内部维护了一个Entry类型的名为table的数组,这个Entry类是ThreadLocalMap的静态内部类,并且该Entry持有存储它的ThreadLocal的弱引用。

  static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

这个Entry其实就是对要共享的数据进行了简单的封装。
我们再来看一下ThreadLocal的部分源码

    private final int threadLocalHashCode = nextHashCode();
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

ThreadLocal的set方法就是先拿到本线程的ThreadlocalMap然后将该ThreadLocal对象以及要存储的value交给ThreadLocalMap去存储,ThreadLocalMap会利用ThreadLocal的threadLocalHashCode该字段hash值以及如今table的大小-1做一些操作得到要存储在table的位置的索引,并将value封装为Entry存放在table中,并且ThreadLocalMap会做判断是否要对table数组进行扩容。可见ThreadLoca就是就是一个封装相关方法帮助我们存储与拿取值的类。threadLocalHashCode该字段的利用斐波那契求得hash值这种hash值分布的更均匀。
现在我们来看看looper中如何使用ThreadLocal
我们从looer.prepare()方法开始看起

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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的时候Looer会先利用Looper的静态成员变量ThreadLocal sThreadLocal来获取当前线程的Looper如果拿到了当前现成的looper说明该线程已经prepare过了就会抛出异常,如果当前线程的第一次prepare则Looper会创建一个Looper对象并利用sThreadLocal存储到当前线程的ThreadLocalMap的table中。
可见Looper内部的静态变量sThreadLocal是查找各个线程Looper的重要索引。
我们再来看一下Handler

    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这个是handler最全的构造方法,我们关注一下这个Callback参数

   public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }

这个是Handler的一个内部接口,只有一个handleMessage()方法注意这个handler方法是返回值的跟handler内部的方法同名
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }
    

我们来看一下这个callback应用到的地方

    Message的重要字段:
    :callbcak字段是一个Runnalbe类型的,handler.Post()方法会将runnable封装为Message字段,就是将要执行的动作封装在其中。
    : target字段是handler类型用来告诉looer将他交给哪一个Handler来处理它
   
   
   
   public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
     private static void handleCallback(Message message) {
        message.callback.run();
    }

查看dispatchMessage()可知如果message设置了callback字段就执行并返回,就不会调用Handler的handlMessage()方法,以及Handler设置的回调接口。当message没有设置该字段的时候,怎么处理Message,如果处理该Message的Handler设置了回调就先执行该回调的handleMessage()方法,如果该方法返回true就说明回调已经成功处理消息,不需要handler调用自己的handlMessage()方法了,但是如果回调返回false那么就交给Handler调用它的handlMessage()方法再处理一遍,说明回调的优先级要更改。
感觉dispatch()很有模板方法的味道,Handler严格控制Message处理的方式与顺序,并且callback相当于hook()函数。

原文地址:https://www.cnblogs.com/FCY-LearningNotes/p/14568192.html