讲讲Handler实现原理

各主要类作用:

Handler:负责发送消息及处理消息
Looper:复制不断的从消息队列中取出消息,并且给发送本条消息的Handler
MessageQueue:负责存储消息
Message:消息本身,负责携带数据

分发流程:

初始化消息队列,创建messageQueue并绑定到Looper上。

Handler的sendMessage发起消息处理流程开端,创建Message并放入到MessageQueue中,由Looper的无限循环任务唤醒阻塞,开始分发Message,执行Message的Runable之后,调用保存的handler的handleMessage方法,回到handler实现结束消息流程。

主要类的关联关系:

ThreadLocal中获取Looper对象,说明Looper是线程独立的,即主线程(MainThread)持有。

MessageQueue是在Looper的构造方法创建,说明Looper是关联的MessageQueue的。采用next持有message对象引用,形成链表实现。

Looper的loop方法,发起for(;;)无限循环,在message.next()中或者没有对象阻塞,或者有对象进行message执行。

Message中callback保存runable对象用来执行,next保存下一个message用来实现链表,target用来执行runable的run方法。

延申问题:

那么,loop的for(;;)会阻塞线程,那么主线程是如何在阻塞时接触阻塞的呢?按上面的说法是没有其他线程进行唤醒操作的

如果你了解下linux的epoll你就知道为什么不会被卡住了,先说结论:阻塞是有的,但是不会卡住 
主要原因有2个

  1. epoll模型 
    当没有消息的时候会epoll.wait,等待句柄写的时候再唤醒,这个时候其实是阻塞的。

  2. 所有的ui操作都通过handler来发消息操作。 
    比如屏幕刷新16ms一个消息,你的各种点击事件,所以就会有句柄写操作,唤醒上文的wait操作,所以不会被卡死了。

在代码ActivityThread.main()中:
public static void main(String[] args) {
        .... 
        //创建Looper和MessageQueue对象,用于处理主线程的消息
        Looper.prepareMainLooper(); 
        //创建ActivityThread对象
        ActivityThread thread = new ActivityThread();  
        //建立Binder通道 (创建新线程)
        thread.attach(false); 
        Looper.loop(); //消息循环运行
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

thread.attach(false);便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程,具体过程可查看 startService流程分析,这里不展开说,简单说Binder用于进程间通信,采用C/S架构。

猜你喜欢

转载自blog.csdn.net/qq_34203714/article/details/109459904
今日推荐