Android 手写一套Handler

上一篇,详细分析了原理和handler机制的源码(传送门 -> https://blog.csdn.net/yaojie5519/article/details/100579131

这一篇,将自己动手“丰衣足食”,尝试手写一套Handler代码

一、分析

按照上一篇内容,画出UML类图(只包含主要的部分方法)如下:

注意几个类的关系和主要方法。

上一篇内容有几个点需要补充一下:

1、在MessageQueue中,添加消息和取出消息,都有同步锁的存在,这是为了防止多个线程同时操作消息队列,防止同时读写,导致消息错乱。

所以我们在手写的时候也需要一个锁。

 2、在activity中使用handler,若不是静态内部类,handler对象会隐式的持有一个外部类对象(一般是该activity)。这样就有内存泄漏的风险,容易导致OOM,那么解决方法是什么:

1)在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。

2)将handler声明为静态类

静态类不持有外部类对象,这时便不会有内存泄漏风险。不过此时就需要对activity有一个弱引用了

public static class MyHandler extends Handler {

     WeakReference<Activity> mWeakReference;
     public MyHandler(Activity activity) {
         mWeakReference=new WeakReference<Activity>(activity);
     }

     @Override
     public void handleMessage(Message msg){
         final Activity activity=mWeakReference.get();
         if(activity!=null){
             if (msg.what == 1){
                 //刷新UI
             }
          }
     }
}

3、loop()的无限循环会不会很消耗CPU资源?

答案是不会。当MessageQueue中无消息对象时,主线程会阻塞在loop的queue.next()中的nativePollOnce()方法里。此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 

二、上手

Handler:

public class Handler {

    private Looper mlooper;
    private MessageQueue mQueue;

    public Handler() {
        mlooper = Looper.myLooper();
        mQueue = mlooper.messageQueue;
    }

    public void sendMessage(Message message){
        message.target = this;
        mQueue.enqueueMessage(message);
    }

    public void handlerMessage(Message message){

    }

    public void dispatchMessage(Message message){
        handlerMessage(message);
    }
}

Looper:

public class Looper {

    final MessageQueue messageQueue;
    private static ThreadLocal<Looper> threadLocal = new ThreadLocal<>();

    public Looper() {
        messageQueue = new MessageQueue();
    }

    public static void prepare() {
        if (threadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        threadLocal.set(new Looper());
        System.out.println("looper初始化");
    }

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

    public static void loop() {
        Looper me = myLooper();
        Message msg;
        for (; ; ) {
            msg = me.messageQueue.next();
            if (msg == null || msg.target == null){
                System.out.println("Looper:空消息");
                continue;
            }
            System.out.println("Looper:looper轮询到了消息,发送消息");
            msg.target.dispatchMessage(msg);
        }
    }
}

Message:

public class Message {

    public int what;
    public Object object;
    public Handler target;

    private static final Object sPoolSync = new Object();
    private static Message sPool;
    Message next;
    int flags;
    private static int sPoolSize = 0;

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    @Override
    public String toString() {
        return object.toString();
    }
}

MessageQueue:

public class MessageQueue {

    Message[] mItems;
    int mPutIndex;
    private int mCount;
    private int mTakeIndex;

    Lock mlock;
    Condition getCondition;
    Condition addCondition;

    public MessageQueue() {
        mItems = new Message[50];
        mlock = new ReentrantLock();
        getCondition = mlock.newCondition();
        addCondition = mlock.newCondition();
    }

    /**
     * 取消息出列
     * @return
     */
    Message next(){
        Message msg = null;
        try {
            mlock.lock();
            while (mCount <= 0){
                System.out.println("MessageQueue:队列空了,读锁阻塞");
                getCondition.await();
            }
            msg = mItems[mTakeIndex];
            mItems[mTakeIndex] = null;
            mTakeIndex = (++mTakeIndex >= mItems.length)?0:mTakeIndex;
            mCount--;

            addCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            mlock.unlock();
        }

        return msg;

    }

    /**
     * 添加消息入列
     * @param message
     */
    public void enqueueMessage(Message message){

        try {
            mlock.lock();
            while (mCount >= mItems.length){
                System.out.println("MessageQueue:队列空了,写锁阻塞");
                addCondition.await();
            }
            mItems[mPutIndex] = message;
            mPutIndex = (++ mPutIndex >= mItems.length)?0:mPutIndex;
            mCount ++;
            getCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            mlock.unlock();
        }

    }
}

三、测试

private void test(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                handler = new Handler(){
                    @Override
                    public void handlerMessage(Message message) {
                        super.handlerMessage(message);
                        System.out.println("Test:"+Thread.currentThread().getName()+"线程接收到:"+message.object);
                    }
                };
                Looper.loop();
            }
        }).start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.object = Thread.currentThread().getName() + "发送了消息";
                handler.sendMessage(message);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.object = Thread.currentThread().getName() + "发送了消息";
                handler.sendMessage(message);
            }
        }).start();

    }

结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KWMax

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值