当前位置:

首页 > 系统应用 > 3.3 Handler消息传递机制浅析

3.3 Handler消息传递机制浅析

本节引言 前两节已经把 Android 里两种事件处理机制梳理过了,事件响应这一块,核心也就是这两类。接下来要展开的是 Activity 中 UI 组件之间的信息传递工具——Handler。这个概念不少人都听过:出于线程安全考虑,Android 不允许在 UI 线程之外直接操作 UI。所以,很多界面

本文目录

    本节引言

    前两节已经把 Android 里两种事件处理机制梳理过了,事件响应这一块,核心也就是这两类。接下来要展开的是 Activity 中 UI 组件之间的信息传递工具——Handler。这个概念不少人都听过:出于线程安全考虑,Android 不允许在 UI 线程之外直接操作 UI。所以,很多界面刷新的动作,本质上都要借助 Handler 去通知 UI 组件完成更新。当然,更新界面不只有这一种办法,也可以用 runOnUiThread(),再进一步,还有更高级的事务总线方案。不过这一节先把 Handler 讲透:它到底是什么、是怎么跑起来的、常用方法有哪些,以及它在子线程和主线程中的使用差别,都会一并说明清楚。

    1.学习路线图:

    2.Handler类的引入:

    3.Handler的执行流程图:

    流程图解析: 相关名词

    • UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
    • Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象
    • Message:Handler接收与处理的消息对象
    • MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
    • Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!

    简单点说:

    当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!

    4.Handler的相关方法:

    • void handleMessage(Message msg):处理消息的方法,通常是用于被重写!
    • sendEmptyMessage(int what):发送空消息
    • sendEmptyMessageDelayed(int what,long delayMillis):指定延时多少毫秒后发送空信息
    • sendMessage(Message msg):立即发送信息
    • sendMessageDelayed(Message msg):指定延时多少毫秒后发送信息
    • final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息 如果是参数为(int what,Object object):除了判断what属性,还需要判断Object属性是否为指定对象的消息

    5.Handler的使用示例:

    1)Handler写在主线程中

    在主线程中,因为系统已经初始化了一个Looper对象,所以我们直接创建Handler对象,就可以进行信息的发送与处理了!

    代码示例: 简单的一个定时切换图片的程序,通过Timer定时器,定时修改ImageView显示的内容,从而形成帧动画

    运行效果图:

    实现代码:

      
      
     

    MainActivity.ja va:

    public class MainActivity extends Activity {  
    //定义切换的图片的数组id  
        int imgids[] = new int[]{  
            R.drawable.s_1, R.drawable.s_2,R.drawable.s_3,  
            R.drawable.s_4,R.drawable.s_5,R.drawable.s_6,  
            R.drawable.s_7,R.drawable.s_8  
        };  
        int imgstart = 0;  
        final Handler myHandler = new Handler()  
        {  
          @Override  
          //重写handleMessage方法,根据msg中what的值判断是否执行后续操作  
          public void handleMessage(Message msg) {  
            if(msg.what == 0x123)  
               {  
                imgchange.setImageResource(imgids[imgstart++ % 8]);  
               }  
            }  
        };  
        
          
        @Override  
        protected void onCreate(Bundle sa vedInstanceState) {  
            super.onCreate(sa vedInstanceState);  
            setContentView(R.layout.activity_main);  
            final ImageView imgchange = (ImageView) findViewById(R.id.imgchange);  
    //使用定时器,每隔200毫秒让handler发送一个空信息  
            new Timer().schedule(new TimerTask() {            
                @Override  
                public void run() {  
                    myHandler.sendEmptyMessage(0x123);  
    }  
            }, 0,200);  
        }  
    } 

    2)Handler写在子线程中

    如果是Handler写在了子线程中的话,我们就需要自己创建一个Looper对象了!创建的流程如下:

    1 )先直接调用Looper.prepare(),这样就能给当前线程建立一个Looper;与此同时,它的构造方法也会顺带把配套的MessageQueue一并创建好。2 )接着创建Handler对象,并重写handleMessage()方法,这样来自其他线程的消息就能在这里被接收和处理。3 )最后调用Looper.loop()方法,Looper也就正式启动了。

    使用示例: 输入一个数,计算后通过Toast输出在这个范围内的所有质数

    实现代码: main.xml:

      
          
        

    MainActivity.ja va:

    public class CalPrime extends Activity  
    {  
        static final String UPPER_NUM = "upper";  
        EditText etNum;  
        CalThread calThread;  
        // 定义一个线程类  
        class CalThread extends Thread  
        {  
            public Handler mHandler;  
    public void run()  
            {  
                Looper.prepare();  
                mHandler = new Handler()  
                {  
                    // 定义处理消息的方法  
                    @Override  
                    public void handleMessage(Message msg)  
                    {  
                        if(msg.what == 0x123)  
                        {  
                            int upper = msg.getData().getInt(UPPER_NUM);  
                            List nums = new ArrayList();  
                            // 计算从2开始、到upper的所有质数  
                            outer:  
                            for (int i = 2 ; i <= upper ; i++)  
                            {  
                                // 用i处于从2开始、到i的平方根的所有数  
                                for (int j = 2 ; j <= Math.sqrt(i) ; j++)  
                                {  
                                    // 如果可以整除,表明这个数不是质数  
                                    if(i != 2 && i % j == 0)  
                                    {  
                                        continue outer;  
                                    }  
                                }  
                                nums.add(i);  
                            }  
                            // 使用Toast显示统计出来的所有质数  
                            Toast.makeText(CalPrime.this , nums.toString()  
                                , Toast.LENGTH_LONG).show();  
                        }  
                    }  
                };  
                Looper.loop();  
            }  
        }  
        @Override  
        public void onCreate(Bundle sa vedInstanceState)  
        {  
            super.onCreate(sa vedInstanceState);  
            setContentView(R.layout.main);  
            etNum = (EditText)findViewById(R.id.etNum);  
            calThread = new CalThread();  
            // 启动新线程  
            calThread.start();  
        }  
        // 为按钮的点击事件提供事件处理函数  
        public void cal(View source)  
        {  
            // 创建消息  
            Message msg = new Message();  
            msg.what = 0x123;  
            Bundle bundle = new Bundle();  
            bundle.putInt(UPPER_NUM ,  
                Integer.parseInt(etNum.getText().toString()));  
            msg.setData(bundle);  
            // 向新线程中的Handler发送消息  
            calThread.mHandler.sendMessage(msg);  
        }  
    } 

    PS:本例子来自于《Android疯狂讲义》~

    本节小结

    本节对Android中的Handler事件传递进行了简单的分析,要分清楚Handler,Message,MessageQueue, Loop的概念,以及Handler写在主线程中以及子线程中的区别!

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    系统应用
    相关文章 更多
    PPT 2016怎么设置演讲者备注查看模式
    PPT 2016怎么设置演讲者备注查看模式

    在进行公开汇报或路演演讲时,许多人会选择将提示内容写在PPT的演讲者备注里,这样一来,既能有效避免忘词带来的尴尬局面,又不会因为提示内容出现在页面上而影响观众的视觉体验。然而,不少使用PPT 2016的朋友却不知道该如何调出这个专属的演讲者备注查看模式。别担心,今天就为大家详细整理了清晰明了的操作步

    百度网盘网页版直接登录
    百度网盘网页版直接登录

    百度网盘网页版直接登录入口为https://pan.baidu.com,打开浏览器输入该网址即可登录,无需安装客户端,支持多设备同步、文件共享及在线预览等功能。 你是不是也遇到过这样的场景:临时需要用电脑查看网盘里的文件,却不想特地下载一个庞大的客户端?或者,只是想快速分享个链接,却觉得打开手机Ap

    谷歌翻译官网网页版入口地址
    谷歌翻译官网网页版入口地址

    多语种覆盖能力 首先,它支持超过100种语言之间的即时互译,从全球主流语系到冰岛语、拉脱维亚语这类区域性小语种,都能找到对应方案,覆盖范围相当广泛。对于不确定源语言的情况,系统自带的语种自动识别功能就派上了大用场,粘贴文本后瞬间就能判定语种并启动翻译,操作门槛极低。 面对德语、法语、日语这些语法结构

    雨课堂网页版登陆官网
    雨课堂网页版登陆官网

    雨课堂官网为https://www.yuketang.cn/,支持网页端登录和微信小程序多端使用,提供课前预习、课中互动、课后复习全流程教学服务。 雨课堂的网页版登录入口到底在哪里?这几乎是每位初次接触该平台的师生都会问的问题。别急,下面我们就来完整梳理一下雨课堂系统的在线登录方法,以及最核心的官网

    PPT形状合并剪切功能
    PPT形状合并剪切功能

    PowerPoint形状的“合并形状”功能:从基础叠加到专业级图形创作 经常有朋友问,为什么在PowerPoint里把几个形状叠在一起,却做不出那种酷炫的镂空或者融合效果?问题可能不在于你的想法,而在于方法——你很可能忽略了PPT里一个叫做“合并形状”(布尔运算)的核心工具。它就像图形设计的“后台开

    3.4 TouchListener PK OnTouchEvent + 多点触碰
    3.4 TouchListener PK OnTouchEvent + 多点触碰

    本节引言: 如题,本节给大家带来的是TouchListener与OnTouchEvent的比较,以及多点触碰的知识点! TouchListener是基于监听的,而OnTouchEvent则是基于回调的!下面通过两个简单的例子来加深 大家的理解! 1.基于监听的TouchListener 代码示例:

    3.5 监听EditText的内容变化
    3.5 监听EditText的内容变化

    本节引言: 在前面我们已经学过EditText控件了,本节来说下如何监听输入框的内容变化! 这个再实际开发中非常实用,另外,附带着说下如何实现EditText的密码可见 与不可见!好了,开始本节内容! 1.监听EditText的内容变化 从题意就能看出来,这里走的其实还是基于监听的事件处理机制。前面

    3.6 响应系统设置的事件(Configuration类)
    3.6 响应系统设置的事件(Configuration类)

    本节引言: 这一节要聊的 Configuration 类,本质上就是用来描述手机设备配置信息的,比如屏幕方向、触摸屏的交互方式等。做过 ROM 定制的朋友对它通常不会陌生,在:frameworks/base/core/ja va/android/content/res/Configuration.j

    3.7 AsyncTask异步任务
    3.7 AsyncTask异步任务

    本节引言: 本节给大家带来的是Android给我们提供的一个轻量级的用于处理异步任务的类:AsyncTask,我们一般是 继承AsyncTask,然后在类中实现异步操作,然后将异步执行的进度,反馈给UI主线程~ 好吧,可能有些概念大家不懂,觉得还是有必要讲解下多线程的概念,那就先解释下一些概念性的东

    3.8 Gestures(手势)
    3.8 Gestures(手势)

    本节引言: 周六不休息,刚剪完了个大平头回来,继续码字~ 这一节来到第三章的收尾部分,聊的是 Gestures(手势)。用过魅族手机的朋友,对这套交互方式大多不会陌生:比如从 home 键两侧向屏幕内滑动,就能直接调出后台任务列表。其实,手势一旦用到应用里,用户体验往往会明显提升。举个最直观的例子,

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。