欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android消息机制原理,仿写Handler Looper源码解析跨线程通信原理--之仿写模拟Handler(四)

程序员文章站 2022-07-14 19:53:43
...

前篇总结:上一篇实现了用Looper管理消息队列和消息循环,但是消息的发送和消息处理都是在Looper中进行的。写一个子线程使用这样的Looper怎么才能获取到loop()死循环消息队列取出的消息呢?用回调!callBack!

第四节 仿写Handler来发送消息,实现回调接口,处理消息

Handler类的功能很简单:1.就是发送消息到本线程(Handler和Looper在同一个线程)的Looper对象的消息队列里。 2.实现消息回调方法处理消息。

public class TestThreadMsg5 {
    public static Handler mainHandler;

    public static void main(String[] args){
        Looper.prepare();

        mainHandler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                System.out.println("主线程:"+Thread.currentThread().getId()+"  收到消息:"+msg.obj);
                if (msg.what == 1){
                    System.out.println("主线程:"+Thread.currentThread().getId()+"  do work!");
                    System.out.println("");
                    System.out.println("");
                }
                return false;
            }
        });

        Thread1 t1 = new Thread1();
        t1.start();

        Looper.loop();//阻塞式,死循环遍历消息列表
    }

    /**
     * 模拟Handler,主要职责:
     *   1.把消息放入到线程对应的Looper对象的消息队列里
     *   2.处理消息
     * Handler就是一个线程处理消息的钩子或者叫句柄,一个线程可以有很多个Handler实例
     * 所以每个Message对象都有个target,指明消息对象由哪个Handler进行处理
     * 而每个线程只允许有一个Looper对象与之对应,只有一个Looper对象自然也就只有一个消息队列了。
     *
     */
    public static class Handler {
        Looper mLooper = null;
        LinkedTransferQueue mQueue = null;
        Callback mCallback = null;

        //回调接口
        public interface Callback {
            public boolean handleMessage(Message msg);
        }

        public Handler(Callback callback) {
            this.mLooper = Looper.myLooper();
            this.mQueue = mLooper.mQueue;
            this.mCallback = callback;
        }

        public void dispatchMessage(Message msg){
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
        }

        public final void sendMessage(Message msg){
            msg.target = this;
            mQueue.put(msg);
        }
    }

    /**
     * 消息实体类,主要职责:
     *  1.承载消息内容
     *  2.指定由谁来处理我(消息)
     */
    static class Message {
        public int what;
        public Object obj;
        public Handler target;//消息对应的Handler
    }

    /**
     * 模拟Looper,主要职责:
     *  1.创建管理消息队列
     *  2.不断死循环取出消息队列里的消息
     *  3.处理消息(后续交给Handler处理)
     *  说明:Looper用静态prepare()方法实例化自己,每个线程只能实例化一个Looper对象
     *  Looper的myLooper()方法,在哪个线程调用就返回哪个线程的Looper对象(通过ThreadLocal实现)
     */
    static class Looper{
        //ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        LinkedTransferQueue mQueue;//阻塞式消息队列,每一个线程对应一个消息队列

        private Looper(){
            this.mQueue = new LinkedTransferQueue();//初始化阻塞式消息队列
        }

        /**
         * 初始化Looper,并放到线程变量里,
         * 这里做了限制,每个线程只能有一个Looper对象,因为是死循环多个也无意义
         */
        public static void prepare() {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper());
        }

        /**
         * 从线程变量里取出,当前线程对应的Looper
         * @return
         */
        public static Looper myLooper() {
            return sThreadLocal.get();
        }

        /**
         * 取出当前线程里的Looperd对象开始死循环遍历消息队列
         */
        public static void loop(){
            final Looper me = myLooper();
            //模拟LOOP的循环方法
            for (;;) {
                Message msg = null;
                try {
                    msg = (Message) me.mQueue.take();
                    msg.target.dispatchMessage(msg);//交个Message指定的Handler去处理
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public LinkedTransferQueue getQueue() {
            return mQueue;
        }
    }


    static class Thread1 extends Thread{
        @Override
        public void run() {
            super.run();
            for (;;) {
                try {
                    Message msg = new Message();
                    msg.what = 1;
                    msg.obj = "主线程去更新UI吧";
                    System.out.println("子线程:"+Thread.currentThread().getId()+"  发送消息:"+msg.obj);
                    mainHandler.sendMessage(msg);//向主线程的Looper的消息队列里添加消息
                    Thread.sleep(5000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

首先说明下:1.在一个线程中可以有很多个Handler实例。 2.在线程中new Handler时 Handler会从Looper的myLooper()方法拿到当前线程的Looper对象,也顺便拿到Looper的Message队列。

        Looper的loop()循环遍历出的消息怎么交给Handler处理的?答案就是消息实体类Message,Message中的target指定了该消息由哪个Handler对象处理。Looper调用Handler的dispatchMessage派送消息给Handler,Handler再通过回调给用户处理。

基本模拟了Android中的Handler、Looper线程通信,但是Android的MessageQueue不是用LinkedTransferQueue实现的,不过也是采用阻塞链表实现的有兴趣的可以看看。