【第二课】深入理解Handler

简要讲解Handler是做什么的

我们知道,在Android中,app启动会启动一个进程一个线程——UI线程,UI线程是主线程,并且不允许这个线程阻塞超过5秒,一旦超过5秒就会ANR。

所以较为耗时的工作(网络请求、文件读写)一般都是开一个线程来处理的,但其他的工作线程不可以直接操作Android的UI,UI只能在UI线程操作。所以就需要一个进程间通信机制来让工作线程的消息传递到UI线程,从而在UI线程改变UI。

这个通信机制就是Handler,普遍的做法就是通过重载Handler的handleMessage方法来接收来自工作线程的消息,方法内写操作UI的部分。在线程内调用handler.sendMessage()来发送Message消息。

如果你已经会用以上这种用法,请继续阅读。

(这一课默认你是了解Java线程的,而且了解线程之间的通信在Android中是怎么使用Handler的。如果还不了解可以去网上找找资料,自己动手写写。)

道理我都懂,可是Handler为什么这么NB?

我们接触了很多回调函数,比如OnCreate……就比如眼前的Handler里的handlerMessage方法吧,本质上说就是一个普通的方法嘛,在等待着你去继承这个类,然后重载它,凭什么它可以在线程发送消息的时候可以调用这个函数?它到底是什么机制?

这就要从Activity的运行机制讲起了:

Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例,应用程序的主线程不断地从这个消息队例中获取消息(Looper),然后对这些消息进行处理(Handler),这样就实现了通过消息来驱动应用程序的执行。

参考资料:http://blog.csdn.net/luoshengyang/article/details/6817933

看不懂上面这段没关系,我们现在换种方式来说:

现在我们有个消息队列(MessageQueue),每当我们sendMessage的时候就会把消息push到这个队列中。主线程就是从这个消息队列中读取出这一条一条的消息的,取出消息,分发给Handler。

问题来了,我们说起来这个过程容易,主线程怎么知道这个队列中有没有新消息啊?隔几毫秒就去检查一下队列,轮询?

事实上还真是“轮询”,但不是想象中那种低效的轮询,而是:

整个应用程序就是围绕这个消息队列无限循环的,如果队列有消息,主线程就把它取出来,分发给相应的Handler处理,如此循环,直到应用程序退出。

HaHa~应用程序本身就在不停的处理消息的,不能说是笨拙的轮询吧,人家把生命都献给了轮询呢!

//Looper是什么?
//TODO:简单理解就是一个操作这个消息队列的类,这个坑作者以后填哈~

我好讨厌用Handler啊!

为啥讨厌用Handler呢?因为用到Handler的时候都是需要工作线程的运行结果反馈,去更新UI,既要开个Thread->

又要new一个Runnable->

还要在run函数里写sendMessage,把数据封装一番再send->

到了handlerMessage里把数据解封装,再去操作UI……

这一来二去,实现一个小小的需求构造了不少的类,实例化了不少的对象,通过构造函数传递了不少的数据,敲了好多代码,这不是人懒嘛,所以讨厌~

那么好吧,觉得麻烦可能是你真的不太会用Handler。

Handler尽量满足你的各种“偷懒”需求

  • 普通需求:我想从工作线程向主线程传递几个普通参数而已。

    //用普通的handler.sendMessage(message)就好
    //Message的构造:
    Message message=Message.obtain();//不用new Message()这个在后文会解释
    message.arg1=1; //可以附带两个int类型的简单参数
    message.arg2=2; //可以附带两个int类型的简单参数
    message.what=3; //消息码,用来识别消息的
    message.obj=new Object(); //一个Object类型的啦
    //这几个参数对于普通需求来说就够了,比如加载图片、刷新进度条等等。
  • 二逼需求:我就想知道工作线程有没结束,成功还是失败了吱一声就好,不要废话信息太多。
    handler.sendEmptyMessage(what)//发送空消息
    //够简洁了吧,不用构造Message了,成功失败的直接用what判断就好了。
    //适用于比如,微博微信点赞、发布评论等等
  • 文艺需求:我的数据类型比较复杂,拆分成参数实在麻烦。
    Message message=Message.obtain();
    Bundle bundle=new Bundle();//需求复杂,也只好用Bundle来承载了
    bundle.putSerializable("xxx",MyObject);//MyObject必须实现Serializable接口,java的序列化你懂得。
    
    message.setData(bundle);
    
    //除此之外bundle还可以put很多很多的int、String、Byte做value的键值对,Bundle应该比较熟悉了吧~
  • 淡定需求:我工作线程的消息不着急告诉主线程,延迟一会儿发送吧。
    sendMessageDelayed(Message msg, long delayMillis)//延迟
    sendMessageAtTime(Message msg, long uptimeMillis)//定时
    
    sendEmptyMessageDelayed(int what, long delayMillis)
    sendEmptyMessageAtTime(int what, long uptimeMillis)
  • 处女座需求:我UI处理的代码就两行,放到工作线程里刚刚好。我想要我的UI处理代码可以复用,不写重复的代码,搞的整个java文件乱糟糟的。
    //这……看来要祭出绝招了!
    ……//省略前面的,从run()开始:
    public void run() {
        …… //工作线程里的各种工作
    
        handler.post(new Runnable() {//调用了post,立马执行里面的东西
                @Override
                public void run() {
                    //UI操作
                }
        });
    
    }
    //handler允许你直接用post函数放一个Runnable进去,然后立马执行。
    //你看,这样是不是既简洁又符合单线程的感觉?而且这个Runnable还能独立出来复用呢~

Message的构造方式为什么要用Message.obtain()

直接引用大神的解释:

对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。

Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。

总结

Handler用熟练了其实也不会觉得麻烦的,多实践。还有一点很重要,那就是你在探究某个API的时候多想想它能应用到什么场合,多想想为什么要提供这个接口。培养阅读源码的能力也很重要哦~哪怕只是看看结构怎么写的。

原文来自个人博客:【第二课】深入理解handler

by:cyhhao http://blog.zhusun.in/cyhhao/

时间: 2024-11-07 19:50:31

【第二课】深入理解Handler的相关文章

第二课:IOS(App)UIImage控件与TextField控件学习

作为一名实习生我是1.3.5在办公室工作,2.4.6去另一个地方听课学习IOS(app)课程,为了不落下课程,我准备每天晚上把落下的课程自学一遍,把不懂的记下等去听课的时候问老师,希望自己能跟上学习的步伐,不浪费时间.这一课是前几天听的,今天一起也写上了. 第二课:IOS(App)UIImage控件与TextField控件的学习,代码如下 一:UIImage控件代码:把图片添加到视图中并设置大小,这里没有牵涉到图片背景的颜色设置,我猜想应该是没必要去设置的吧,因为没有按钮功能的话背景颜色也看不到

【Web探索之旅】第二部分第二课:服务器语言

内容简介 1.第二部分第二课:服务器语言 2.第二部分第三课预告:框架和内容管理系统 第二部分第二课:服务器语言 介绍了Web的客户端,我们来谈谈Web的服务器端. 既然客户端有客户端的编程语言(HTML,CSS和JS),那么我们服务器端岂能逊色呢,对吧. 服务器端也有不少种编程语言.这些编程语言写成的程序会在服务器端的电脑上被执行. 如果说客户端的语言编写的程序决定了我们的网页的外观,那么服务器端的语言编写的程序决定了网页的功能和如何与用户交互. 你也许会问:"既然我们可以用HTML,CSS和

【C语言探索之旅】 第二部分第二课:进击的指针,C语言的王牌!

内容简介 1.课程大纲 2.第二部分第二课: 进击的指针,C语言的王牌 3.第二部分第三课预告: 数组 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型

Ng第二课:单变量线性回归(Linear Regression with One Variable)

二.单变量线性回归(Linear Regression with One Variable) 2.1  模型表示 2.2  代价函数 2.3  代价函数的直观理解 2.4  梯度下降 2.5  梯度下降的直观理解 2.6  梯度下降的线性回归 2.7  接下来的内容 2.1  模型表示 之前的房屋交易问题为例,假使我们回归问题的训练集(Training Set)如下表所示: 我们将要用来描述这个回归问题的标记如下: m                代表训练集中实例的数量 x          

【自动语音识别课程】第二课 语音信号分析

[传送门] [自动语音识别课程]第一课 统计语音识别介绍 原文地址:http://blog.csdn.net/joey_su/article/details/36414877 转载请注明出处,欢迎交流. 概述 针对ASR的语音信号分析 特征 频谱分析 倒谱分析 标准特征:MFCC和PLP分析 动态特征 第一课的结尾提到了语音识别的框图,下图展示了信号分析技术在语音识别系统中的位置: 我们先来认识下语音的产生过程: 语音是在发音器官和声道共同作用下产生的.说话时,声带振动发出具有一定周期特性(基音

【Linux探索之旅】第二部分第二课:命令行,世界尽在掌握

内容简介 1.第二部分第二课:命令行,世界尽在掌握 2.第二部分第三课预告:文件和目录,组织不会亏待你 命令行,世界尽在掌握 今天的标题是不是有点霸气侧漏呢? 读者:"小编,你为什么每次都要起这么非主流的标题呢?不能愉快地玩耍么?" 小编:"那我问你,老子他为什么要写<道德经>咧?" 读者:"为什么咧?" 小编:"因为老子愿意!" 开个小玩笑轻松一下 O(∩_∩)O~ 没办法,不能不激动,因为我们终于来到了这一刻,

【Linux探索之旅】第三部分第二课:流、管道、重定向,三管齐下

内容简介 1.第三部分第二课:流.管道.重定向,三管齐下 2.第三部分第三课预告:监视系统活动,滴水不漏 流.管道.重定向,三管齐下 这一课我们来学一些非常有用的内容,而且相当有意思,而且内容很多,而且有可能颠覆你的三<观>(毕竟三管齐下,不颠覆三观也难). 今天的标题中的三个名称,听上去就怪怪的.什么流,管道,重定向,都啥玩意啊.不过希望学完这课,大家能够有拨云见雾的感觉. 到目前为止,我们已经学习了不少Linux的命令了,也已经比较熟悉命令行的用法了.其最基本用法是这样的: 在终端输入命令

【Linux探索之旅】第一部分第二课:下载Linux,免费的噢

 内容简介 1.第一部分第二课:下载Linux,免费的噢 2.第一部分第三课预告:测试并安装Ubuntu 下载Linux,免费的噢 大家好,上一课我们认识了非常"霸气侧漏"的Linux操作系统. 也知道了它的吉祥物:企鹅,叫Tux(燕尾服的意思),而且它是一只雄性的企鹅,爷们,24K纯滴.(这个不重要好不,小编...) 我们还提到了什么是操作系统,Linux的历史和不同的Linux发行版.也确定了我们后续课程要使用的Linux发行版:Ubuntu.幸好,在各个Linux发行版(每个发

【C++探索之旅】第一部分第二课:C++编程的必要软件

 内容简介 1.第一部分第二课:C++编程的必要软件 2.第一部分第三课预告:第一个C++程序 C++编程的必要软件 经过上一课之后,大家是不是摩拳擦掌,准备大干一场了呢. 这一课我们来做一些C++开发前的准备工作. 编程的必要工具 依你看,什么软件对编程来说是必要的呢?如果你认真学了上一课,那你至少可以说出一种吧. 对了,就是编译器.这个重要的程序可以把你的源代码(用高级语言如C语言写的指令)转换成电脑可以理解的二进制码(只包含0和1的,类似 01100110001111011101010.