handler机制的原理_Handler流程讲解

Handler怎么使用?

1.创建Handler实例。

2.创建Message对象建议使用Message的静态方法obtain()构建。

3.给Message对象赋值。

4.Handler.sendMessage()方法把Message发送出去。

5.在Handler里重写它的handlerMessage方法,用来处理接收到的Message。

Handler机制:

Handler:把Message添加到MssageQueue里,处理Looper发送过来的Message。

Looper:取出MessageQueue的Message,将Message发送到Handler。

Mssage:储存信息。

MessageQueue:储存Handler发送过来的Message

简单说:

当一个应用启动时,会初始化一个UI线程,UI线程中又初始化了Looper,创建Looper的时候又创建了MessageQueue。当Handler把 Messgae发送到MessageQueue里,然后Looper循环的取出发给Handler,由Handler处理这个信息。

Hander,Looper,MessageQueue,Message的全程协作的关系就好比一个餐厅的整体运作关系

Handler好比点餐员
Looper好比后厨厨师长。
MessageQueue好比订单打单机。
Message好比一桌一桌的订单。


接下来我们回顾下我们餐厅点餐的场景,餐厅点餐分为标准点餐和特殊点餐,我们分解来看。

标准流程

    1、首先进入一家店,通过点餐员点餐把数据提交到后厨打单机。

    2、然后厨师长一张一张的拿起订单,按照点餐的先后顺序,交代后厨的厨师开始制作。

    3、制作好后上菜,并标记已做好的订单。

特殊流程

     1、订单为延迟订单,比如客人要求30分钟后人齐了再制作,这时会把该订单按时间排序放到订单队列的合适位置,并通过SystemClock.uptimeMillis()定好闹铃。至于为什么用uptimeMillis是因为该时间是系统启动开始计算的毫秒时间,不受手动调控时间的影响。

      2、如果打单机中全是延迟订单,则下令给后厨厨师休息,并在门口贴上免打扰的牌子(needWake),等待闹铃提醒,如有新的即时订单进来并且发现有免打扰的牌子,则通过nativeWake()唤醒厨师再开始制作上菜。

      3、但是为了提升店铺菜品覆盖,很多相邻的店铺都选择合作经营,就是你可以混搭旁边店的餐到本店吃,此时只需点餐员提交旁边店的订单即可,这样旁边店的厨师长就可以通过打单机取出订单并进行制作和上菜。

总结

一家店可以有多个点餐员,但是厨师长只能有一个。打单机也只能有一个。

映射到以上场景中,一家店就好比一个Thread,而一个Thread中可以有多个Handler(点餐员),但只能有一个Looper(厨师长),一个MessageQueue(打单机),和多个Message(订单)。


根据以上的例子我们类比看下源码,充分研究下整个机制的流程,和实现原理。

Looper的工作流程

ActivityThread.main();//初始化入口    1. Looper.prepareMainLooper(); //初始化          Looper.prepare(false); //设置不可关闭              Looper.sThreadLocal.set(new Looper(quitAllowed)); //跟线程绑定                    1.1.Looper.mQueue = new MessageQueue(quitAllowed); //Looper和MessageQueue绑定                    1.2.Looper.mThread = Thread.currentThread();    2. Looper.loop();        2.1.myLooper().mQueue.next(); //循环获取MessageQueue中的消息              nativePollOnce(); //阻塞队列                  native -> pollInner() //底层阻塞实现                        native -> epoll_wait();        2.2.Handler.dispatchMessage(msg);//消息分发

myLooper().mQueue.next()实现原理

  • 通过myLooper().mQueue.next() 循环获取MessageQueue中的消息,如遇到同步屏障 则优先处理异步消息.

  • 同步屏障即为用Message.postSyncBarrier()发送的消息,该消息的target没有绑定Handler。在Hnandler中异步消息优先级高于同步消息。

  • 可通过创建new Handler(true)发送异步消息。ViewRootImpl.scheduleTraversals方法就使用了同步屏障,保证UI绘制优先执行。

Handler.dispatchMessage(msg)实现原理

  • 优先回调msg.callback。

  • 其次回调handler构造函数中的callback。

  • 最后回调handler handleMessage()。


Hander发送消息的流程

1.Handler handler = new Handler();//初始化Handler        1.Handler.mLooper = Looper.myLooper();//获取当前线程Looper。        2.Handler.mQueue = mLooper.mQueue;//获取Looper绑定的MessageQueue对象。2.handler.post(Runnable);//发送消息        sendMessageDelayed(Message msg, long delayMillis);            sendMessageAtTime(Message msg, long uptimeMillis);                Handler.enqueueMessage();//Message.target 赋值为this。                    Handler.mQueue.enqueueMessage();//添加消息到MessageQueue。

MessageQueue.enqueueMessage()方法实现原理

  • 如果消息队列被放弃,则抛出异常。

  • 如果当前插入消息是即时消息,则将这个消息作为新的头部元素,并将此消息的next指向旧的头部元素,并通过needWake唤醒Looper线程。

  • 如果消息为异步消息则通过Message.when长短插入到队列对应位置,不唤醒Looper线程。

经常有人问为什么主线程的Looper阻塞不会导致ANR?

  • 首先我们得知道ANR是主线程5秒内没有响应。

  • 什么叫5秒没有响应呢?Android系统中所有的操作均通过Handler添加事件到事件队列,Looper循环去队列去取事件进行执行。如果主线程事件反馈超过了5秒则提示ANR。

  • 如果没有事件进来,基于Linux pipe/epoll机制会阻塞loop方法中的queue.next()中的nativePollOnce()不会报ANR。

  • 对于以上的例子来说,ANR可以理解为用户进行即时点餐后没按时上菜(当然未按时上菜的原因很多,可能做的慢(耗时操作IO等),也可能厨具被占用(死锁),还有可能厨师不够多(CPU性能差)等等。。。),顾客发起了投诉,或差评。但如果约定时间还没到,或者当前没人点餐,是不会有差评或投诉产生的,因此也不会产生ANR。

    8d5bfc1ae3fef2e72ddc1faee01547cf.png5a7da6a6ddd1564e62e15e2c3d820614.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值