美文网首页
Android消息机制----Handler运行机制

Android消息机制----Handler运行机制

作者: 善笃有余劫 | 来源:发表于2018-07-25 00:05 被阅读16次

    消息机制是什么

    Handler是用于线程之间的消息传递的工具,作用是从一个线程切换到另一个线程。所谓的Android消息机制就是Handler的运行机制。通常我们使用Handler从子线程转到UI线程去更新UI。

    Android消息机制概述

    Handler的运行需要MessageQueueLooper的支撑。线程内使用ThreadLocal存储线程数据包括Looper。Handler使用ThreadLocal获取每个线程的Looper

    一些内容概念

    MessageQueue:消息队列,存储消息并以队列形式插入删除数据。
    Looper:一个无限循环,用于接收最新的消息处理
    ThreadLocal:ThreadLocal并不是一个Thread,而是Thread的局部变量。可以视为内部通过一个Map(实际是内部类ThreadLocalMap)存取数据,存取数据只在同一线程有效。

    Handler消息机制流程

    首先在当前线程创建Handler,同时handler采用当前线程的Looper构建内部消息循环系统(就可以开始等待消息的进入)。(主线程ActivityThread默认有Looper,假设当前线程没有会抛异常。只需要为当前线程创建Looper即可)

    然后消息传递线程使用handler的post/send方法将消息加入到MessageQueue队列中。Handler内部的Looper发现新的消息到来,就会处理消息(调用handlerMessage方法)。消息也就被切换到Handler的创建线程中。

    以上就是整个的消息循环机制,可能有点绕。但是我总是试图用某种比喻来解释这个过程(以下是我的理解,可能不对):

    瞎说大白话

    A是一个强大的国家(A线程),而B是一个弱小的国家(B线程)。按道理,B国家需要向A进贡物品(消息Message)。而AB之间有一个很大沟壑,无法直接运输。这时强大的A想了一个办法,由A生产一个可以飞的运输工具(Handler),派到B国家中向A国家驾驶(send方法)。同时A国家这边必须由后勤人员部(ThreadLoacal)派遣自己国家的守城门人员(Looper)日夜守在城门看是否有进贡。当然从B到A这条航线(MessageQueue)会有多个进贡排列进来,守城人员必须一个个装卸(MessageQueue next)和处理(handlerMessage)。

    补充
    给线程创建Looper

    fun thread() {
            Thread(Runnable {
                Looper.prepare()//给线程添加looper
                val handler = Handler()// 如果没有Looper.prepare() 报异常 Can't create handler inside thread that has not called Looper.prepare()
                Looper.loop() //开启消息循环
            }).start()
        }
    

    Android消息机制分析

    前面对整个的消息机制进行了概述,对整个消息机制有了了解。而接下来具体分析消息机制中几个成员的具体工作原理(Handler、ThreadLoacal 、MessageQueue 、Looper)。

    面试问题

    1.为什么不能在子线程更新UI

    因为Android的Ui控件不是线程安全的,在多线程更新UI会使UI控件状态不可预期。如果使用加锁机制,会使UI访问机制变得复杂,同时访问的效率也会降低。所以使用单线程模型处理UI控件,而我们只需要转到主线程更新UI即可。

    2.主线程中的Looper.loop()一直无限循环为什么不会造成ANR?

    主线程中的Looper.loop()一直无限循环为什么不会造成ANR?

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

    也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。

    当然我们可以这样理解,Android本身就像是一个高速旋转等待处理事件的传送带

    3.Handler的sendMessage和Post方法的异同

    如下两个方法是等价的

    Handler handler=new Handler();
    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                mTest.setText("post");//更新UI
                            }
                        });
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                         Message message = new Message();
                        message.obj = "handleMessage";
                        message.what = 0;
                        myHandler.sendMessage(message);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 0:
                        mTest.setText((String) msg.obj);//更新UI
                        break;
                }
            }
        };
    

    相当于直接将handler.post里面的代码移到了Handler 的handleMessage方法内部。

    handler.post内部的run方法已经是handler looper所在的线程了,所以可以直接更新UI 这时可以将线程获取的值发送到UI去更新界面。而handler.post本质上还是使用了send方法

    结果就是handler.post更加清爽和简洁。但是如果需要控制流程,就只能使用sendMessage方法

    相关文章

      网友评论

          本文标题:Android消息机制----Handler运行机制

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