美文网首页
Handler原理分析

Handler原理分析

作者: Noblel | 来源:发表于2017-12-30 19:17 被阅读0次

    作为一个开发小白,我以前写代码是这样的

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            ......
        }
    };
    

    但是有个问题
    This Handler class should be static or leaks might occur (anonymous android.os.Handler)

    这个Handler class应该是static,否则可能会内存泄漏。学习了新的写法。

    private static class MyHandler extends Handler {
        //保持对Activity的引用
        private final WeakReference<MainActivity> mActivityWeakReference;
        
        //通过构造方法传入Activity
        public MyHandler(MainActivity activity) {
            mActivityWeakReference = new WeakReference<>(activity);
        }
    
        @Override
        public void handleMessage(Message msg) {
            BaseActivity activity = mActivityWeakReference.get();
            if (activity == null) {
                super.handleMessage(msg);
                return;
            }
            switch (msg.what) {
                case DOWNLOAD_FAILED:
                    ....
                    break;
                case DOWNLOAD_SUCCESS:
                    .....
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    }
    

    使用的时候直接调用

    private final MyHandler mHandler = new MyHandler(this);
    
    //使用Handler进行延时操作,实际上发送的也是Message
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            imageView.setVisibility(View.VISIBLE);
        }
    },1000);
                
    //使用子线程下载图片
    new Thread(new Runnable() {
        @Override
        public void run() {
            Bitmap bitmap = downloadImage();
    
            Message msg = Message.obtain();
            msg.obj = bitmap;
            msg.what = bitmap==null?DOWNLOAD_FAILED:DOWNLOAD_SUCCESS;
    
            handler.sendMessage(msg);
        }
    }).start();   
    

    所以我决定看一下学习一下Handler的机制。

    为什么postDelayed()发送的也是Message?

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    public final boolean postDelayed(Runnable r, long delayMillis)
    {
        //方法1
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    
    /**
     * 方法1
     */
    private static Message getPostMessage(Runnable r) {
        //获取消息,到这里我们就明白了为什么是Message了
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
    
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    /**
     * 除了sendMessageAtFrontOfQueue()方法之外,其它的发送消息方法最终都会走到这里
     */ 
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //消息阻塞队列
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        //sendMessageAtFrontOfQueue返回的是enqueueMessage(queue, msg, 0);
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //先看一下Message再看怎么消息排列
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    Message

    作用:包含任意数据对象的消息,用于发送给Handler

    获取Message实例的方式

    //获取Message实例的方式
    Message msg1 = new Message();
    Message msg1 = Message.obtain();
    Message msg2 = Handler.obtainMessage();
    
    public final class Message implements Parcelable {
        
        /**
         * 用户自定义消息码
         */
        public int what;
        
        /**
         * arg1和arg2是Message自带的用来传递一些轻量级存储int类型的数据,比如进度条的数据等。
         * 通过这个数据是通过Bundle的方式来转载的
         */ 
        public int arg1;
        
        public int arg2;
        
        /**
         * 用来传递一些对象
         */
        public Object obj;
        
        /**
         * 线程通信时候使用
         */ 
        public Messenger replyTo;
        
        ....
    }
    
    /**
     * 平时获取消息会调用此方法,sPool为当前消息对象池,sPool实际就是单项链表
     * 当sPool = null的时候才会new Message(),如果不是,就从sPool里面拿实例
     */
    public static Message obtain() {
        //锁对象,在定义时候初始化,随后只读不写
        synchronized (sPoolSync) {
            if (sPool != null) {
                //典型的链表结构
                //比如 原本消息是  1(sPool) - 2(m.next) - 3 取走了1
                //现在就剩下 2(sPool) - 3了  
                Message m = sPool;  //
                sPool = m.next;  //相当于把2置顶
                m.next = null;  // 相当于把原来的1的下一个节点引用置为null,因为此时m.next(1)还在指向2
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        //如果对象池中没有就返回一个新的Message
        return new Message();
    }
    

    MessageQueue

    /**
     * 用于将消息排队,提供消息入队的方法
     * when 就是SystemClock.uptimeMillis() + delayMillis,就是你创建消息的时间+你要延迟的时间
     */ 
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
    
        synchronized (this) {
            //判断是否退出
            msg.markInUse();
            msg.when = when;
            //以前的消息链表的头部
            Message p = mMessages;
            boolean needWake;
            //什么时候为when == 0 呢? 就是使用sendMessageAtFrontOfQueue
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                //置为头部,最前面,因为需要最先发送
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //一直循环判断时间,确定合适的位置
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
    
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                //需要唤醒发送就调用底层线程间通信发送(现在还没了解=-=)
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;
    
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                //把前一个Message存起来置为当前Message的next
                next = sPool;
                //把当前的Message放在最前面
                sPool = this;
                sPoolSize++;
            }
        }
    }
    

    ActivityThread:

    public static void main(String[] args) {   
        ....
        //初始化主线程Looper
        Looper.prepareMainLooper();
        ....
        //系统启动的时候就会执行looper的loop方法
        Looper.loop();
    }
    

    Looper:

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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();
        }
    }
    
    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));
    }
    
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    
    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;
        ....
        //一直循环
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ....
            try {
                //分发消息,调用Handler的dispatchMessage方法内部调用的是我们常常重写的handleMessage方法
                msg.target.dispatchMessage(msg);
                ....
            } finally {
                ...
            }
            ....
            //回收一些资源
            msg.recycleUnchecked();
        }
    }
    

    ThreadLocal

    ThreadLocal并不是本地线程,而是线程本地变量
    就是使Looper在不同的线程下获取的值不同,主线程是主线程的,Thread1是Thread1的
    使用场景:当某些数据时以线程为作用域而且不同的线程获得的数据不同

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    void createMap(Thread t, T firstValue) {
        //可见Thread中有个ThreadLocalMap
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    
    /**
     * 专门存放要进行本地化的线程数据的Map
     */
    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
        table = new Entry[INITIAL_CAPACITY];
        //这里放的位置和HashMap的计算方式一样,可以去看HashMap的原理
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        //设置阈(yu)值
        setThreshold(INITIAL_CAPACITY);
    }
    
    /**
     * 存值操作,有了Map就直接存值
     */
    private void set(ThreadLocal<?> key, Object value) {
    
        // We don't use a fast path as with get() because it is at
        // least as common to use set() to create new entries as
        // it is to replace existing ones, in which case, a fast
        // path would fail more often than not.
    
        Entry[] tab = table;
        int len = tab.length;
        //这里还是和HashMap一样,,,可见HashMap中用了多么巧妙的算法
        int i = key.threadLocalHashCode & (len-1);
    
        for (Entry e = tab[i];
             e != null;//循环的时候判断是否e为空
             e = tab[i = nextIndex(i, len)] // 如果e != null 那么就存到i + 1的位置,如果超过了大小就放在0
             ) {
            ThreadLocal<?> k = e.get();
    
            //从弱引用中获取值
            if (k == key) {
                e.value = value;
                return;
            }
    
            if (k == null) {
                //替换Entry
                replaceStaleEntry(key, value, i);
                return;
            }
        }
    
        //tab[i] 为空,也就是表中没有这个数据
        tab[i] = new Entry(key, value);
        int sz = ++size;
        //更新了数据而且数据量过大了就重新hash
        if (!cleanSomeSlots(i, sz) && sz >= threshold)
            rehash();
    }
    
    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();
    }
    
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    

    总结一下

    用下郭霖大神的图。

    Handler流程图.png

    明白了原来有些事情需要我们去钻研。去深入,给自己加油 打call~!

    相关文章

      网友评论

          本文标题:Handler原理分析

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