手把手带你实现Handler

在开始实现之前我们需要一个Handler模型进行推导

手把手带你实现Handler_第1张图片
handler.png

ThreadLocal:

呵呵呵,没有我你们能干啥?

synchronized:笑而不语

Lock:楼上sb?还没被开除?

Condition:2楼sb

Handler:气氛Hi起来!动次打次!

Message:朋友圈帮我集个赞!

Looper:.......

MessageQueue:退群了

旁白:我们通过上图的模型可以推导出,要想实现Handler机制少不了以下的一些队友的配合

1.Message

TA就是一个对象,封装了一些信息,使用者可以将自己想要的信息传到里面去!里面只有几个成员变量,没别的!

private int what;//用过Handler的肯定经常用吧

private Object;//跟上面的成员变量一个意思

private Hander target;//这是个重点,为什么要封装一个Handler对象呢?因为最终处理消息的是Handler啊.如果没有这个对象,我们如何(调用)把消息传递给Handler的handleMessage方法呢?

2.MessageQueue

a.MessageQueue 是一个链表结构的消息队列(数组实现)

b.主要提供存,取,对存取的线程进行锁控制,避免多线程并发访问的问题.

c.MessageQueue可提供的功能列表:

void enqueueMessage(Message message);//将消息对象添加到链表中

Message next();//从链表中取出消息对象

boolean hasNext();//消息队列中的数据是否为空

3.Looper

死循环!死循环!死循环!死循环!死循环!死循环!死循环!死循环!

Looper中可提空的功能列表:

void prepare();//初始化Looper,将Looper绑定到ThreadLocal

void loop();//开始死循环的从MessageQueue中取出消息对象.

Looper myLooper();//获取ThreadLocal中存储的Looper对象

4.Handler

负责发送消息,处理消息

可提供的功能列表:

void handleMessage(Message message);

void sendMessage(Message message);//发送消息就是将你的Message对象放到MessageQueue中去

void dispatchMessage(Message message);//没别的,就是调用了一下handleMessage,之所以会有这个方法是因为我们更合理的进行封装.当Looper.loop方法循环取消息时会调用这个方法.

5.ThreadLocal

在线程中扮演了很重要的角色

引:ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性.

在Handler中使用ThreadLocal来进行数据隔离,目的就是更好的隔离Looper对象,毕竟我们的Looper是存储在了ThreadLocal 的map中.

6.Lock,Condition

为了解决线程锁,队列为空,或者满员的问题,当队列为空或者队列满员的情况我们要通过Lock去阻塞(消息不能被添加到队列中,取出消息的时候也同理),直到队列中有消息被消费了(处理了).毕竟我们得队列长度是有限的嘛,要不然就内存溢出了嘛,老天爷会惩罚你的嘛.

Condition:与Lock配对使用,我们这里之所以用Condition而不用synchronized的原因就是Condition 与Lock配合,可以指定"谁"来解锁.显而易见的用synchronized来实现是非常麻烦的,Lock和Condition 更适合复杂的并发场景.

OK!我们经过了上面的小图片的推导,大体的结构就已经出来了

首先Handler中的代码:

public class Handler {

    private MessageQueue mMessageQueue;
    private Looper myLooper;
    public void handleMessage(Message message){

    }
    //handler 在主线程中初始化
    public Handler(){
        //拿到Looper
        myLooper = Looper.myLooper();
        //拿到Looper中的消息队列

        mMessageQueue = myLooper.messageQueue;

    }
    public void dispathMessage(Message message){
        handleMessage(message);
    }
    public void sendMessage(Message message){
        //发送消息就是将消息实体入队到消息队列中
        message.target = this;
        mMessageQueue.enqueueMessage(message);

    }

}

Looper中的代码:

public class Looper {


    MessageQueue messageQueue;
    public static void prepare(){
        if (mThreadLocal.get() != null){
            throw new RuntimeException("Only on Looper may be created per thread");
        }
        mThreadLocal.set(new Looper());
    }
    public Looper(){
        messageQueue = new MessageQueue();
    }
    private static final ThreadLocal mThreadLocal = new ThreadLocal<>();

    public static void loop(){
       Looper me =  myLooper();
       if (me ==null){
           throw  new RuntimeException("thread looper is null.call Looper.prepare()");
       }
       //获取到loop中的消息队列
        MessageQueue messageQ = me.messageQueue;
        for (;;){

            if (!messageQ.hasNext()){
                continue;
            }else {
                Message message = messageQ.next();
                //如果消息为null,继续处理下一个
                if (message ==null){
                    continue;
                }
                //拿到消息,将消息发送给Handler
                message.target.dispathMessage(message);
            }
        }
    }
    public static Looper myLooper(){
        if (mThreadLocal.get() ==null){

            throw new RuntimeException("not call Looper.prepare()");
        }
        return mThreadLocal.get();
    }
}

Message中的代码:

public class Message {
     Handler target;//消息的处理对象
    public int what;
    public Object object;

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

MessageQueue中的代码

public class MessageQueue {

    /**
     * 到底能不能再子线程中更新UI?
     * Android 通过判断当前线程是否是ViewRootImpl的创建线程来检查是否可以更新UI
     * 调用View.addView的时候会调用初始化ViewRootImpl,也就是说如果我在子线程中addView,
     * 那么我就可以在子线程中更新View.
     */
    private int MAX_QUEUE = 50;
    /**
     *  消息队列应该有上限,否则会造成内存溢出
        当队列没有消息的时候需要阻塞,直到有消息进来
        当队列消息满的时候需要阻塞,直到有消息被处理
     */
    Message[] messageQueue;

    private Lock mLock;//锁对象,为了可以控制消息队列什么时候可以继续出队或者入队
    private Condition popCondition;//可以选择性的解锁
    private Condition pushCondition;

    private int messageQueueCout;//队列中的消息的当前是数量
    private int pushIndex;//入队时的索引
    private int popIndex;//出队时的索引
    //出队消息:运行在子线程中

    public void enqueueMessage(Message message){
        try {
            //加锁类似于synchronized (),因为Condition可以选择性解锁
            mLock.lock();
            //当消息队列满了,子线程停止发送消息,阻塞
            //为了避免多个子线程同级唤醒,导致的单次判断问题.使用while 不断进行检查.
            while (messageQueueCout == MAX_QUEUE){
                pushCondition.await();
            }
            //将消息推进数组中
            messageQueue[pushIndex] = message;
            pushIndex++;
            if (pushIndex == MAX_QUEUE){
                pushIndex = 0;
            }
            messageQueueCout++;
            //如果有产品被生产,通知消费者可以继续消费Message
            popCondition.signalAll();//??
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            mLock.unlock();
        }

    }
    //出队消息:运行在主线程中(消费队列中的消息)
    public Message next(){
        Message message = null;
        try {
            //当消息队列为空的时候阻塞消费者,让消费者不能继续消费消息
            mLock.lock();
            while (messageQueueCout ==0){
                popCondition.await();
            }

            message = messageQueue[popIndex];
            messageQueue[popIndex] = null;//当一个数据被出队时,释放内存
            popIndex++;
            if (popIndex == MAX_QUEUE){
                popIndex=0;
            }
            //当队列数量不满时通知子线程可以继续入队消息
            messageQueueCout--;

            //通知生产者可以继续生产Message
            pushCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            mLock.unlock();
        }

        return message;
    }
    public boolean hasNext(){
        return messageQueue.length!=0;
    }
    public MessageQueue(){
        //初始化消息队列
        messageQueue = new Message[MAX_QUEUE];
        mLock = new ReentrantLock();//初始化锁对象
        this.pushCondition = mLock.newCondition();
        this.popCondition = mLock.newCondition();

    }

}

好的!我们来写个Main方法调用一下!

public class Main {

    public static void main(String[] args) {

        Looper.prepare();
        Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message message) {
                System.out.println(message);
            }
        };
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message m = new Message();
                m.object="hello";
                mHandler.sendMessage(m);
            }
        }).start();
        Looper.loop();
    }
}

这就是为什么在Activity main方法中会调用 Looper.prepare()...Looper.loop();
因为你要将自己持久化到内存中去嘛!要不然就死掉了嘛!
通过一个死循环+Handler
当我们在子线程中创建Handler的时候,也要模仿Activity的Handler创建方式才对嘛!
在哪个线程中创建了Handler 对于Handler本身来说谁就是主线程.因为对于Handler来说线程是相对关系的!

  public class Activity{
    public static main(String[] args){
      ......
      Looper.prepareMainLoop();
      ............
      Looper.loop();
    }
  }

你可能感兴趣的:(手把手带你实现Handler)