您当前的位置: 首页 >  android
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

handler相关学习(一)手写Android消息机制

沙漠一只雕得儿得儿 发布时间:2020-02-01 18:19:37 ,浏览量:0

Android  的消息机制主要是指Handler得运行机制

以上模型的解释:

         1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。

         2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。

         3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。

这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler, Message, MessageQueue,Looper。

下面我们就围绕着这四个主要对象,来看下handler的运行机制,以及手写一个简易的handler消息机制。

Android消息处理机制
  • 一、创建全局唯一Looper对象和全局唯一MessageQueue消息对象:

  • 二、Activity中创建Handler

  • 三、消息发送,Message进入MessageQueue队列

  • 四、消息处理,looper循环获取message消息处理

  • 五、消息分发到自己的handlerMessage()方法 

手写Android消息处理机制

其实主要就是上面流程中的四个对象的创建。

  • 一、MessageQueue就是负责message消息的入队和出队,很简单,我们用一个阻塞队列来实现
public class DnMessageQueue {

    //阻塞队列
    BlockingQueue blockingQueue = new ArrayBlockingQueue(50);

    public void enqueueMessage(DnMessage message) {
        try {
            blockingQueue.put(message);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //从消息队列中取出消息
    public DnMessage next() {
        try {
            return blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return  null;
    }
}
  • 二、上面是我们接收handler发出消息的容器,也就是存放message的地方,下面就要创建handler的消息入队操作,就是平时我们使用的mHandler.sendMessage(message)方法中的message对象通过handler的enqueue方法添加到消息队列的容器中:
public class DnHandler {

    private DnLooper dnLooper;
    private DnMessageQueue dnMessageQueue;

    public DnHandler() {
        dnLooper = DnLooper.myLooper();
        if (dnLooper == null) {
            throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
        }
        dnMessageQueue = dnLooper.mQueue;
    }

    public void handleMessage(DnMessage msg) {
    }

    public void sendMessage(DnMessage message) {
        //将消息放入消息队列
        enqueueMessage(message);
    }

    private void enqueueMessage(DnMessage message) {
        //赋值当前消息
        message.target = this;

        //使用dnMessageQueue,将消息传入
        dnMessageQueue.enqueueMessage(message);
    }

    public void dispatchMessage(DnMessage message) {
        handleMessage(message);
    }
}

这里的handler类的作用主要两点:一是enQueue消息到消息队列中;二是消息分发给对应的target。

  • 三、消息入队后,就轮到looper上场行进消息队列的轮询,将加入到消息队列中的消息取出来
public class DnLooper {
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    final DnMessageQueue mQueue;

    private DnLooper(){
        mQueue = new DnMessageQueue();
    }

    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one DnLooper may be created per thread");
        }
        sThreadLocal.set(new DnLooper());
    }

    public static DnLooper myLooper() {
        return sThreadLocal.get();
    }

    public static void loop() {
        //从全局ThreadLocalMap中获取唯一, looper对象
        DnLooper dnLooper = myLooper();
        DnMessageQueue mQueue = dnLooper.mQueue;

        while (true){
            DnMessage message = mQueue.next();
            if(message != null ){
                message.target.dispatchMessage(message);
            }
        }
    }
}
  • 四、其中的Message对象
public class DnMessage {
    //消息标志
    public int what;
    //消息内容
    public Object obj;
    //Handler对象
    public DnHandler target;
}
  • 五、最终,为了使用我们自己的handler消息机制,我们测试类的入口是需要写在工程的test中,使用注解@Test来执行。因为要是再工程中的话程序在ActivityThread中会帮我们创建系统的handler。
public class DNActivityThread {

    @Test
    public void main(){

        //创建全局唯一主线程Looper对象
        DnLooper.prepare();

        //创建Handler对象
        final DnHandler dnHandler = new DnHandler(){
            @Override
            public void handleMessage(DnMessage msg) {
                super.handleMessage(msg);
                System.out.println(msg.obj.toString());
            }
        };

        new Thread(new Runnable() {
            @Override
            public void run() {
                DnMessage message = new DnMessage();
                message.what = 1;
                message.obj = "大家好!";
                dnHandler.sendMessage(message);
            }
        }).start();

        //获取消息
        DnLooper.loop();

    }

}

运行后,我们可以看到会打印出“大家好”这条消息。当然这个handler只是一个简化版的,为了理解handler消息机制的运行,系统的handler还有挂起、唤醒、延迟插入消息等完善的处理方案。

本项目地址:https://github.com/buder-cp/DesignPattern/tree/master/buder_DN_handler_thread

相关的handler学习博客推荐:

基础篇:

https://www.jianshu.com/p/b4d745c7ff7a?tdsourcetag=s_pcqq_aiomsg

深入篇:

https://blog.csdn.net/qian520ao/article/details/78262289#1-looper-%E6%AD%BB%E5%BE%AA%E7%8E%AF%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%BA%94%E7%94%A8%E5%8D%A1%E6%AD%BB?tdsourcetag=s_pcqq_aiomsg

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.1537s