当前位置:
首页
文章
移动端
详情

手写Android-Handler

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;
    }
}

免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。