【第二课】深入理解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/
【第二课】深入理解Handler的更多相关文章
- 从源码角度深入理解Handler
为了获得良好的用户体验,Android不允许开发者在UI线程中调用耗时操作,否则会报ANR异常,很多时候,比如我们要去网络请求数据,或者遍历本地文件夹都需要我们在新线程中来完成,新线程中不能更新UI, ...
- 【Linux探索之旅】第二部分第二课:命令行,世界尽在掌握
内容简介 1.第二部分第二课:命令行,世界尽在掌握 2.第二部分第三课预告:文件和目录,组织不会亏待你 命令行,世界尽在掌握 今天的标题是不是有点霸气侧漏呢? 读者:“小编,你为什么每次都要起这么非主 ...
- 【Web探索之旅】第二部分第二课:服务器语言
内容简介 1.第二部分第二课:服务器语言 2.第二部分第三课预告:框架和内容管理系统 第二部分第二课:服务器语言 介绍了Web的客户端,我们来谈谈Web的服务器端. 既然客户端有客户端的编程语言(HT ...
- 【C++探索之旅】第一部分第二课:C++编程的必要软件
内容简介 1.第一部分第二课:C++编程的必要软件 2.第一部分第三课预告:第一个C++程序 C++编程的必要软件 经过上一课之后,大家是不是摩拳擦掌,准备大干一场了呢. 这一课我们来做一些C++开发 ...
- 【Linux探索之旅】第一部分第二课:下载Linux,免费的噢
内容简介 1.第一部分第二课:下载Linux,免费的噢 2.第一部分第三课预告:测试并安装Ubuntu 下载Linux,免费的噢 大家好,上一课我们认识了非常“霸气侧漏”的Linux操作系统. 也知道 ...
- 【C语言探索之旅】 第二部分第二课:进击的指针,C语言的王牌!
内容简介 1.课程大纲 2.第二部分第二课: 进击的指针,C语言的王牌 3.第二部分第三课预告: 数组 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言 ...
- 【C语言探索之旅】 第二课:工欲善其事,必先利其器
内容简介 1.课程大纲 2.第一部分第二课:工欲善其事,必先利其器 3.第一部分第三课预告:你的第一个程序 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C ...
- TCP/IP 网络精讲:OSI七层模型(第二课)
内容简介 1.前言 2.第一部分第二课:互联网的创立,OSI七层模型 3.第一部分第三课预告:OSI第一层,连接你的机器 前言 PS:昨天做了课程大纲之后,发现这个坑挖得有点大.不过既然挖了,岂有不跳 ...
- Kotlin入门第二课:集合操作
测试项目Github地址: KotlinForJava 前文传送: Kotlin入门第一课:从对比Java开始 初次尝试用Kotlin实现Android项目 1. 介绍 作为Kotlin入门的第二课, ...
随机推荐
- hdu 1845
一看题意就是二分匹配问题,建边是双向的,两个集合都是n个点 这题的图很特殊,每个点都要与三个点相连,在纸上画了六个点的图就感觉此图最大匹配肯定是六,除以2就是原图的匹配了,就感觉这样的图肯定会达到满匹 ...
- Scala 深入浅出实战经典 第46讲: ClassTag 、Manifest、ClasMainifest TagType实战
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- 【LeetCode】257. Binary Tree Paths
Binary Tree Paths Given a binary tree, return all root-to-leaf paths. For example, given the followi ...
- jenkins svn E175002错误
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true -Dsvnkit.http.sslProtocols='SSLv3' -Dsvnkit.http ...
- Windows Azure 入门系列课程Windows Azure 入门系列课程
Windows Azure 入门系列课程 https://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/NewSeries/A ...
- android:layout_weight
layout_weight 用于给一个线性布局中的诸多视图的重要度赋值. 所有的视图都有一个layout_weight值,默认为零,意思是需要显示多大的视图就占据多大的屏幕空 间.若赋一个高于零的值, ...
- android studio 中查找代码中的硬编码
在Android Studio中同时按下Ctrl + Shift+ F 或者其他自定义的快捷键,打开全局搜索,在全局搜索中输入 ^((?!(\*|//)).)+[\u4e00-\u9fa5] 并打勾 ...
- Rails: No such file or directory - getcwd
这个的意思就是你从一个删除的目录里面运行实例:rails s
- Spring4 MVC Hibernate4集成
Spring4 MVC Hibernate4集成 一. 本文所用环境 Spring4.0.3.RELEASE Hibernate4.3.5.Final Mysql 二. 工程目录 三. ...
- Kruskal算法java版
/** * sample Kruskal.java Description: * kruskal算法的思想是找最小边,且每次找到的边不会和以找出来的边形成环路,利用一个一维数组group存放当前顶点所 ...