美文网首页
Handler消息机制

Handler消息机制

作者: 寒冬_腊月 | 来源:发表于2020-04-30 16:13 被阅读0次

    概念

    Android的UI更新是单线程模型,只能在主线程上操作,在子线程上就要通过使用Handler来进行更新UI的操作
    Handler的运行基于MessageQueue(单链表)和Looper, MessageQueue顾名思义是消息队列。但其实是一个单项链表结构来存储信息Message的。而Looper则是不断去读取消息队列MessageQueue中的信息,Handler的工作主要是发送和接收消息,一个线程只有一个Looper

    Looper

    用于对线程使用消息循环的一个类,在一个线程中调用prepare()方法是为了运行loop, 再调用loop()处理消息直到loop停止

    子线程中创建Handler

    new Thread(new Runnable() {  
       public void run() { 
           //创建消息队列和保存当前的线程
           Looper.prepare();  
           mHandler = new Handler(){  
           @Override  
           public void handleMessage(Message msg) {  
                   //在这里处理传入的消息 
               }  
            };  
            //遍历消息队列
            Looper.loop();  
        };  
     }).start();  
    

    为什么子线程更新UI会报错

    在子线程中更新UI会报下面错误

    Only the original thread that created a view hierarchy can touch its views.
    

    为什么会报这个,在ViewRootImp.java类,中会判断当前线程和主线程
    这个类是在onResume之后创建的

    void checkThread() {
        if (mThread != Thread.currentThread()) {
          throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");
        }
    }
    

    在主线程中更新UI,就可以避免多线程操作UI,导致不同步的一些问题

    如何处理延迟消息的

    1. 消息是通过MessageQueen中的enqueueMessage()方法加入消息队列中的,并且它在放入中就进行好排序,链表头的延迟时间小,尾部延迟时间最大

    2. Looper.loop()通过MessageQueue中的next()去取消息

    3. next()中如果当前链表头部消息是延迟消息,则根据延迟时间进行消息队列会阻塞,不返回给Looper message,知道时间到了,返回给message

    4. 如果在阻塞中有新的消息插入到链表头部则唤醒线程

    5. Looper将新消息交给回调给handler中的handleMessage后,继续调用MessageQueen的next()方法,如果刚刚的延迟消息还是时间未到,则计算时间继续阻塞

    Looper为什么不会阻塞主线程

    因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。

    参考

    掘金

    相关文章

      网友评论

          本文标题:Handler消息机制

          本文链接:https://www.haomeiwen.com/subject/rjozwhtx.html