Android-设计模式与项目架构-03-手写Handle框架

58 阅读4分钟

生产者:往队列添加消息,当队列满的时候,不能再添加消息了,此时block(即消息阻塞了),当生产一个消息的时候,通知消费者有消息可以消费了。

消费者:从队列消费消息(获取),如果队列为空,则block,当消费者消费了一个消息的时候,通知生产者可以再生产消息。

好了废话不多说 直接上代码 代码中有注释

//Message类

/*
* 需要发送的handler
*/
public class Message {
   /**
    * 需要发送的Handler
    */
   public com.kj.handlerlib.Handler target;

   public String what;

   public Message(String what) {
       this.what = what;
   }

   @Override
   public String toString() {
       return "what: " + what;
   }
}

//消息队列MessageqQ

public class MessageQueue {
    
    //消息队列
    private static final int count = 50;
     /**
     * 使用阻塞队列BlockingQueue解决生产者消费者
     * 主要作用是效仿android源码native层的唤醒和堵塞消息队列的问题
     * android源码使用的native方法nativePollOnce(阻塞),nativeWake(唤醒),这里使用另一种java并发提供的阻塞队列类替换
     */
    private final BlockingQueue<Message> mMessageQueue;

    public MessageQueue() {
        mMessageQueue = new ArrayBlockingQueue<>(count);
    }
    public void enqueueMessage(Message msg) {
        try {
            mMessageQueue.put(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /*
     * 获取下一个消息对象 
     * 有消息对象时读取
     */
    public Message next() {
        try {
            return mMessageQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

//消息循环looper类

/*
 * 消息循环类
 */
public class Lopper {
     /**
     * 消息队列
     */
    public MessageQueue mQueue;

    /**
     * ThreadLocal类用来提供线程内部的局部变量。
     * 这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量
     * 提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程
     * <p>
     * ThreadLocal解决多线程的并发问题
     * 每个线程维护一个 ThreadLocalMap 的映射表,
     * 映射表的 key 是 ThreadLocal 实例本身,value 是要存储的副本变量。
     * ThreadLocal 实例本身并不存储值,它只是提供一个在当前线程中找到副本值的 key
     * <p>
     * 每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,
     * value是真正需要存储的Object
     */
    private static final ThreadLocal<Lopper> sThreadLocal = new ThreadLocal<>();

    private Lopper() {
        mQueue = new MessageQueue();
    }
    /**
     * Lopper 初始化
     *
     * @author LuoHao
     * Created on 2018/2/25 14:04
     */
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            sThreadLocal.remove();
            throw new RuntimeException("Only one Looper may be created per Thread");
        }
        sThreadLocal.set(new Lopper());
    }

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

    /**
     * 提供系统动力,让消息队列开始循环工作
     */
    public static void loop() {
        final Lopper me = myLooper();
        if (me == null) {
            sThreadLocal.remove();
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this Thread");
        }
        final MessageQueue queue = me.mQueue;
        // 死循环开始遍历消息并分发
        for (; ; ) {
            // might block
            Message msg = queue.next();
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                System.out.println(" No message indicates that the message queue is quitting.");
                return;
            }
            msg.target.dispatchMessage(msg);
        }
    }
}

//Handler类

public class Handler {
     /**
     * 消息队列
     */
    private final MessageQueue mQueue;

    /**
     * 消息循环
     */
    private final Lopper mLooper;

    public Handler() {
        this(Lopper.myLooper());
    }

    public Handler(Lopper looper) {
        mLooper = looper;
        // 保证MessageQueue与Looper对应性
        mQueue = mLooper.mQueue;
    }

    /**
     * 发送消息
     *
     * @param msg message
     * @author LuoHao
     * Created on 2018/2/26 16:40
     */
    public final void sendMessage(Message msg) {
        // target是Handler本身
        // 多线程中保证Handler的一致性,并且这句是在主线程中调用的,
        // 当其调用自身的handleMessage()时才会有线程切换的效果
        msg.target = this;

        // enqueue a message
        mQueue.enqueueMessage(msg);
    }

    /**
     * 复写该方法 处理消息
     *
     * @author LuoHao
     * Created on 2018/2/26 16:44
     */
    public void handleMessage(Message msg) {
    }

    /**
     * 面向对象设计模式
     * 责任链调度原则
     *
     * @param msg message
     */
    public void dispatchMessage(Message msg) {
        handleMessage(msg);
    }
}
//最后再来一个handler测试类

public class HandlerTest {
     /**
     * 线程数量
     */
    private static final int THREAD_COUNT = 10;

    private static ThreadFactory namedThreadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "common-thread-pool");
        }
    };

    /**
     * Common Thread Pool
     * <p>
     * 手动创建线程池 建议不直接使用Executors.newCachedThreadPool()
     */
    private static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 200,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024),
            namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

    private static ThreadFactory namedThreadFactory2 = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "single-thread-pool");
        }
    };

    /**
     * Single Thread Pool
     * <p>
     * 手动创建线程池代替直接显示new Thread的问题
     */
    private static ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1
            , 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024)
            , namedThreadFactory2, new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        // 手写android 底层Handler机制实现框架
        Lopper.prepare();

        final Handler myHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                System.out.println("handle msg: thread:" + Thread.currentThread().getId() +
                        " Msg: " + msg.toString());
            }
        };

        // 开启多线程
        singleThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("singleThreadPool function thread name: " +
                        Thread.currentThread().getName());
                for (int i = 0; i < THREAD_COUNT; i++) {
                    commonThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("commonThreadPool function thread name: " +
                                    Thread.currentThread().getName());
                            Message msg = new Message(UUID.randomUUID().toString());
                            System.out.println("send Msg: thread: " + Thread.currentThread().getId() +
                                    " Msg: " + msg.toString());
                            myHandler.sendMessage(msg);
                        }
                    });
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        // new Thread().start()

        Lopper.loop();

        // 异常
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}