zoukankan      html  css  js  c++  java
  • 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()函数。

  • 相关阅读:
    is as运算符
    继承,多态
    封装等
    面向对象
    在JDBC中使用带参数的SQL语句
    我的程序库:HiCSDB
    我的程序库:HiCSUtil
    Java中,将ResultSet映射为对象和队列及其他辅助函数
    Java版的对象关系映射实现
    Java中的基本数据类型转换
  • 原文地址:https://www.cnblogs.com/FCY-LearningNotes/p/14568192.html
Copyright © 2011-2022 走看看