手写Handler架构

在了解Handler原理的同时可以翻看源码研究一下Handler架构,下面是本人手写的Handler架构

Message.java

public class Message {

    int what;
    Handler target;

}

Message类我写的很简单,源码中是有很多代码的,这里能够传递值的参数只有what。target对象主要是为了最终能够执行到handleMessage回调方法,具体作用可以在下文代码中可以看到。

MessageQueue.java

/**
 *  互斥队列的通用类
 */
public class MessageQueue {

    //声明阻塞队列
    private BlockingDeque blockingDeque = new LinkedBlockingDeque(50);

    /**
     * 入队(生产者)
     * @param msg
     * @return
     */
    public void enqueueMessage(Message msg) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        try {
            blockingDeque.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 出队(消费者)
     * @return
     */
    public Message next() {
        Message msg = null;
        try {
            msg = (Message) blockingDeque.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }
        return msg;
    }
}

MessageQueue类其实是最核心的地方了,这是一个消息队列,只有两种行文,出队和入队。并且,这是一个生产者、消费者设计模式。BlockingDeque是阻塞队列,在生产者、消费者设计模式中的运用比较常见。

Looper.java

public class Looper {

    static MessageQueue mQueue;
    private static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    private Looper() {
        mQueue = new MessageQueue();
    }


    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

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

    public static void loop(){
        for(;;){
            Message msg = mQueue.next();
            if(msg == null){
                continue;
            }
            msg.target.dispatchMessage(msg);
        }
    }
}

Looper中含有一个消息队列,looper只负责一个任务,那就是无限遍历消息队列,如果队列中有消息,就从队首取出消息,传递给handleMessage回调方法。这里的dispatchMessage方法就是为了执行Handler的回调方法handleMessage。

Handler.java

public class Handler {

    private MessageQueue mQueue;

    public Handler() {
        Looper.prepare();
        Looper looper = Looper.myLooper();
        mQueue = looper.mQueue;
    }

    public void handleMessage(Message msg) {

    }

    public void dispatchMessage(Message msg){
        handleMessage(msg);
    }

    public void sendMessage(Message msg){
        MessageQueue queue = mQueue;
        if (queue != null) {
            enqueueMessage(queue, msg);
        }
    }

    private void enqueueMessage(MessageQueue mQueue, Message msg){
        msg.target = this;
        mQueue.enqueueMessage(msg);
    }
}

Handler负责将消息放进消息队列中,也就是所谓了入队了,sendMessage方法就是让消息入队。

Test.java

public class Test {

    private static Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            System.out.println(String.valueOf(msg.what));
        }
    };
    public static void main(String[] args){

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    Message message = new Message();
                    message.what = i;
                    handler.sendMessage(message);
                }
            }
        }).start();
        Looper.loop();
    }
}

Looper.loop()这个方法不能放入Activity的UI线程,否则会阻塞,这里我新建一个java的启动入口, 我们只需要执行main方法就可以了。

在底层中,ActivityThread是UI线程, Android的启动入口就是这个类的main方法,main方法中已经声明了Looper

Looper.prepareMainLooper();
Looper.loop();

《手写Handler架构》 图片.png

这是我再网上找的一张图, 流程还是比较清晰的。

需要注意的是:
消息入队和出队,必须在不同的线程中执行, 否则线程会阻塞。

    原文作者:NoBugException
    原文地址: https://www.jianshu.com/p/92c8495c6ab1
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞