美文网首页APP & program
手写Android-Handler

手写Android-Handler

作者: h2coder | 来源:发表于2022-07-26 23:45 被阅读0次

    Handler机制,是Android系统的消息队列,一般用于处理主线程的页面绘制等消息处理。

    前言

    Handler除了Java层外,还有Native的部分,但我能力有限,只能仿写一个Java层的Handler,并且支持延时消息。项目地址:MiniHandler

    注:由于消息机制需要使用一个while死循环来让线程不能结束,所以直接将MiniHandler在Android主线程中使用会卡住主线程,所以需要用一个子线程来运行MiniHandler,一般使用HandlerThread,对应到MiniHandlerMiniHandlerThread

    简单介绍

    • 延时消息功能:使用DelayQueue实现,它需要队列中的消息实体实现一个Delayed接口,它继承于Comparable接口,它要求复写一个getDelay()方法,返回延时多长毫秒。以及需要复写compareTo()方法,用于比较2个消息谁先谁后,来决定队列中的消息排序。

    类结构介绍

    • Looper,轮训器,内部包含一个MessageQueue消息队列,并且使用ThreadLocal将每个线程绑定一个Looper。所以一个线程只有一个Looper,一个Looper也只有一个MessageQueue消息队列
    • MessageQueue,消息队列,使用DelayQueue实现队列功能,支持延时消息
    • Message,消息实体类,使用享元模式支持消息对象复用
    • MiniHandler,消息处理器以及消息发送器
    • MiniHandlerThread,原自Android源码中的HandlerThread,改用MiniHandler实现,就是一个带有Handler事件循环的子线程

    原理

    • Handler,发送Message消息到MessageQueue,会被Looper轮训器取出
    • Looper轮训器中,有一个while循环,不断从MessageQueue消息队列中取出消息进行处理,如果队列中没有消息,MessageQueue会阻塞当前线程
    • Handler处理完消息,Message消息回收到池中,复用消息能提高效率,以及减少对象创建

    基本使用

    MiniHandler的API和Handler的一致,2者的Java层API只是类名不同。

    /**
     * Toast任务
     */
    public static final int ACTION_TOAST = 1;
    /**
     * 延时任务
     */
    public static final int ACTION_DELAY = 2;
    
    ////事件处理线程
    MiniHandlerThread handlerThread = new MiniHandlerThread("handler-thread");
    handlerThread.start();
    
    //创建MiniHandler实例,并绑定到MiniHandlerThread
    MiniHandler  eventHandler = new MiniHandler(mHandlerThread.getLooper()) {
        @Override
        public void handleMessage(Message message) {
            super.handleMessage(message);
            long action = message.what;
            if (action == ACTION_TOAST) {
                String msg = message.obj.toString();
                ToastUtil.toast(getApplicationContext(), msg);
            } else if (action == ACTION_DELAY) {
                String delayMsg = message.obj.toString();
                ToastUtil.toast(getApplicationContext(), delayMsg);
            }
        }
    };
    
    //发消息到立即执行事件线程
    eventHandler.sendMessage(Message.obtain(ACTION_TOAST, "Toast~"));
    //或者
    eventHandler.post(new Runnable() {
        @Override
        public void run() {
          ToastUtil.toast(getApplicationContext(), 延时消息~);
        }
    });
    
    //发送延时消息到事件线程
    eventHandler.sendMessageDelayed(Message.obtain(ACTION_DELAY, "延时消息~"), 2000);
    //或者
    eventHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
          ToastUtil.toast(getApplicationContext(), 延时消息~);
        }
    }, 1000);
    
    //退出MiniHnadlerThread
    handlerThread.quitSafely();
    

    源码

    Message消息实体

    消息实体类,使用享元模式支持消息对象复用。为了支持延时消息,消息实体,需要实现一个Delayed接口,它继承于Comparable接口,它要求复写一个getDelay()方法,返回延时多长毫秒。以及需要复写compareTo()方法,用于比较2个消息谁先谁后,来决定队列中的消息排序。

    /**
     * 消息事件实体
     */
    public class Message implements Delayed {
        /**
         * 使用中的标志位
         */
        static final int FLAG_IN_USE = 1;
    
        int flags;
        /**
         * 为了形成消息链表
         */
        Message next;
        /**
         * 对象锁
         */
        public static final Object sPoolSync = new Object();
        /**
         * 消息链表的头节点
         */
        private static Message sPool;
        /**
         * 当前链表中数据的个数
         */
        private static int sPoolSize = 0;
        /**
         * 总共可使用的消息链表大小
         */
        private static final int MAX_POOL_SIZE = 50;
        /**
         * 消息的标识
         */
        public long what;
        /**
         * 消息的附件
         */
        public Object obj;
        /**
         * 消息的处理器
         */
        public MiniHandler target;
        /**
         * 要执行的任务,可为null
         */
        public Runnable callback;
        /**
         * 指定的执行时间,毫秒值
         */
        public long workTimeMillis;
    
        /**
         * 回收Message
         */
        void recycleUnchecked() {
            //把标记设置为使用中
            flags = FLAG_IN_USE;
            //清理所有字段
            what = 0;
            obj = null;
            target = null;
            callback = null;
            workTimeMillis = 0;
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    
        /**
         * 创建一个Message对象
         */
        public static Message obtain() {
            synchronized (sPoolSync) {
                //判断头节点是否null
                if (sPool != null) {
                    //取出头节点
                    Message m = sPool;
                    //将头节点的下一个作为最新的头节点
                    sPool = m.next;
                    //设置需要返回的消息的next为空
                    m.next = null;
                    //清除使用中的标志位
                    m.flags = 0;
                    sPoolSize--;
                    return m;
                }
            }
            //如果消息链表为空 创建新的message
            return new Message();
        }
    
        /**
         * 创建一个Message对象,并绑定处理它的Handler
         */
        public static Message obtain(MiniHandler handler) {
            return obtain(handler, 0);
        }
    
        /**
         * 创建一个Message对象,并绑定处理它的Handler、消息标识what
         */
        public static Message obtain(MiniHandler handler, long what) {
            return obtain(handler, what, null);
        }
    
        /**
         * 创建一个Message对象,绑定消息标识what
         */
        public static Message obtain(long what) {
            return obtain(what, null);
        }
    
        /**
         * 创建一个Message对象,绑定消息标识what、消息附件obj
         */
        public static Message obtain(long what, Object obj) {
            return obtain(null, what, obj);
        }
    
        /**
         * 创建一个Message对象,并绑定处理它的Handler、消息标识what、消息附件obj
         */
        public static Message obtain(MiniHandler handler, long what, Object obj) {
            Message message = obtain();
            message.target = handler;
            message.what = what;
            message.obj = obj;
            return message;
        }
    
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(workTimeMillis
                    - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }
    
        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }
    }
    

    MessageQueue消息队列

    消息队列,使用DelayQueue实现队列功能,支持延时消息

    public class MessageQueue {
        /**
         * 是否退出
         */
        volatile boolean isQuit;
        /**
         * 消息队列
         */
        private final BlockingQueue<Message> mMessageQueue = new DelayQueue<>();
    
        /**
         * 消息入队
         */
        public boolean enqueueMessage(Message message, long uptimeMillis) {
            try {
                message.workTimeMillis = uptimeMillis;
                mMessageQueue.put(message);
                return true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        /**
         * 拿出一条消息
         */
        public Message next() {
            try {
                //如果队列中没有消息,就会阻塞在这里
                return mMessageQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 移除队列中指定Handler的未执行的回调和消息
         */
        public final void removeCallbacksAndMessages(MiniHandler handler) {
            if (handler == null) {
                return;
            }
            List<Message> targetMessages = new ArrayList<>();
            for (Message message : mMessageQueue) {
                if (message.target == handler) {
                    targetMessages.add(message);
                }
            }
            mMessageQueue.removeAll(targetMessages);
        }
    
        public void quit() {
            mMessageQueue.clear();
            isQuit = true;
        }
    }
    

    Looper轮训器

    轮训器,内部包含一个MessageQueue消息队列,并且使用ThreadLocal将每个线程绑定一个Looper。所以一个线程只有一个Looper,一个Looper也只有一个MessageQueue消息队列

    public class Looper {
        private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
        /**
         * 消息队列
         */
        final MessageQueue mMessageQueue;
    
        private Looper() {
            //一个线程,只有一个Looper,一个Looper也只有一个消息队列
            mMessageQueue = new MessageQueue();
        }
    
        /**
         * 把当前线程和Looper进行绑定
         */
        public static void prepare() {
            Looper looper = sThreadLocal.get();
            if (looper != null) {
                throw new RuntimeException("一个线程只能绑定一个Looper,请确保prepare方法在一个线程中只调用一次");
            }
            sThreadLocal.set(new Looper());
        }
    
        /**
         * 获取当前线程的Looper
         */
        public static Looper myLooper() {
            return sThreadLocal.get();
        }
    
        /**
         * 开始循环从队列中取出消息
         */
        public static void loop() {
            //获取当前线程的轮询器
            Looper looper = myLooper();
            MessageQueue queue = looper.mMessageQueue;
            while (!queue.isQuit) {
                Message message = queue.next();
                try {
                    message.target.dispatchMessage(message);
                } finally {
                    //回收Message对象
                    message.recycleUnchecked();
                }
            }
        }
    
        /**
         * 安全退出,会等所有事件都执行完,再关闭
         */
        public void quitSafely() {
            mMessageQueue.quit();
        }
    }
    

    MiniHandler消息处理器

    消息处理器以及消息发送器

    public class MiniHandler {
        /**
         * 消息队列
         */
        private final MessageQueue mMessageQueue;
        /**
         * 事件回调,可以选择构造时传入一个Callback,就可以不需要复写handleMessage()方法进行处理
         */
        private MiniHandler.Callback mCallback;
    
        public MiniHandler() {
            this(Looper.myLooper());
        }
    
        public MiniHandler(Callback callback) {
            Looper looper = Looper.myLooper();
            //Looper没有绑定
            if (looper == null) {
                throw new RuntimeException(
                        "Can't create handler inside thread " + Thread.currentThread()
                                + " that has not called Looper.prepare()");
            }
            mMessageQueue = looper.mMessageQueue;
            mCallback = callback;
        }
    
        public MiniHandler(Looper looper) {
            //Looper没有绑定
            if (looper == null) {
                throw new RuntimeException(
                        "Can't create handler inside thread " + Thread.currentThread()
                                + " that has not called Looper.prepare()");
            }
            mMessageQueue = looper.mMessageQueue;
        }
    
        public interface Callback {
            /**
             * @param msg A {@link android.os.Message Message} object
             * @return True if no further handling is desired
             */
            boolean handleMessage(Message msg);
        }
    
        /**
         * 移除队列中指定Handler的未执行的回调和消息
         */
        public final void removeCallbacksAndMessages() {
            mMessageQueue.removeCallbacksAndMessages(this);
        }
    
        /**
         * 发送消息到消息队列中
         */
        public boolean sendMessage(Message message) {
            return sendMessageDelayed(message, 0);
        }
    
        /**
         * 在主线程执行一个Runnable
         */
        public final boolean post(Runnable task) {
            return sendMessageDelayed(getPostMessage(task), 0);
        }
    
        /**
         * 延迟一段时间后,在主线程执行一个Runnable
         *
         * @param delayMillis 延时时间,毫秒值
         */
        public final boolean postDelayed(Runnable task, long delayMillis) {
            return sendMessageDelayed(getPostMessage(task), delayMillis);
        }
    
        /**
         * 获取一个带Runnable任务的Message
         */
        private static Message getPostMessage(Runnable task) {
            Message m = Message.obtain();
            m.callback = task;
            return m;
        }
    
        /**
         * 发送延时消息
         *
         * @param message     消息
         * @param delayMillis 延时时间
         */
        public final boolean sendMessageDelayed(Message message, long delayMillis) {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(message, System.currentTimeMillis() + delayMillis);
        }
    
        public boolean sendMessageAtTime(Message message, long uptimeMillis) {
            MessageQueue queue = this.mMessageQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, message, uptimeMillis);
        }
    
        private boolean enqueueMessage(MessageQueue queue, Message message, long uptimeMillis) {
            message.target = this;
            return queue.enqueueMessage(message, uptimeMillis);
        }
    
        /**
         * 分发消息给Handler进行处理
         */
        void dispatchMessage(Message message) {
            //如果是post()或postDelayed()发出的任务,则执行这个任务
            if (message.callback != null) {
                handleCallback(message);
            } else {
                //如果在Handler构造时传入了Callback,则回调这个Callback
                if (mCallback != null) {
                    if (mCallback.handleMessage(message)) {
                        return;
                    }
                }
                //都没有,则调用handleMessage(),Handler的子类可以复写该方法进行事件处理
                handleMessage(message);
            }
        }
    
        /**
         * 执行Message绑定的任务
         */
        private static void handleCallback(Message message) {
            message.callback.run();
        }
    
        /**
         * 子类重写该方法进行处理消息
         */
        public void handleMessage(Message message) {
        }
    }
    

    MiniHandlerThread

    原自Android源码中的HandlerThread,改用MiniHandler实现,就是一个带有Handler事件循环的子线程

    /**
     * A {@link Thread} that has a {@link Looper}.
     * The {@link Looper} can then be used to create {@link MiniHandler}s.
     * <p>
     * Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
     */
    public class MiniHandlerThread extends Thread {
        int mPriority;
        int mTid = -1;
        Looper mLooper;
        private MiniHandler mHandler;
    
        public MiniHandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
    
        /**
         * Constructs a HandlerThread.
         *
         * @param name
         * @param priority The priority to run the thread at. The value supplied must be from
         *                 {@link android.os.Process} and not from java.lang.Thread.
         */
        public MiniHandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
    
        /**
         * Call back method that can be explicitly overridden if needed to execute some
         * setup before Looper loops.
         */
        protected void onLooperPrepared() {
        }
    
        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }
    
        /**
         * This method returns the Looper associated with this thread. If this thread not been started
         * or for any reason isAlive() returns false, this method will return null. If this thread
         * has been started, this method will block until the looper has been initialized.
         *
         * @return The looper.
         */
        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
    
            // If the thread has been started, wait until the looper has been created.
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    
        /**
         * @return a shared {@link MiniHandler} associated with this thread
         * @hide
         */
        public MiniHandler getThreadHandler() {
            if (mHandler == null) {
                mHandler = new MiniHandler(getLooper());
            }
            return mHandler;
        }
    
        /**
         * Quits the handler thread's looper safely.
         * <p>
         * Causes the handler thread's looper to terminate as soon as all remaining messages
         * in the message queue that are already due to be delivered have been handled.
         * Pending delayed messages with due times in the future will not be delivered.
         * </p><p>
         * Any attempt to post messages to the queue after the looper is asked to quit will fail.
         * For example, the {@link MiniHandler#sendMessage(Message)} method will return false.
         * </p><p>
         * If the thread has not been started or has finished (that is if
         * {@link #getLooper} returns null), then false is returned.
         * Otherwise the looper is asked to quit and true is returned.
         * </p>
         *
         * @return True if the looper looper has been asked to quit or false if the
         * thread had not yet started running.
         */
        public boolean quitSafely() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quitSafely();
                return true;
            }
            return false;
        }
    
        /**
         * Returns the identifier of this thread. See Process.myTid().
         */
        public int getThreadId() {
            return mTid;
        }
    }
    

    相关文章

      网友评论

        本文标题:手写Android-Handler

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