文档章节

Android 第十四课——Handler Looper Message

learn_more
 learn_more
发布于 2015/02/12 14:25
字数 1340
阅读 218
收藏 9

1、基础概念

1)android.os.Handler 

2)主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 

3)应用程序一旦启动,Android UI 这个主线程的生命周期就开始了,然而,Android UI 线程并不是线程安全的,也就是说,更新UI只能在主线程中同步更新,子线程中异步操作是危险的。所以,项目中如果我们直接new Thread 内部去更改Android UI,往往会报错误如下:

    java.lang.RuntimeException: Can't create handler inside thread that has not called

为了避免错误发生,那么更新Android UI 必须在主线程中操作,具体如何操作呢?Handler就发挥了特的作用。Handler的使用同时也会带来许多相关的知识,下面一一讲解。


2、实例化

1)采用默认的方式 new Handler();项目中很少使用这种方式。如果他是主线程中运行的,那么这个handler对象内部绑定了一个Looper对象Looper.getMainLooper();Looper对象是用来干嘛的呢? Looper类是用来为一个线程开启一个消息循环。可以这样获取对应的线程:handler.getLooper().getThread()。默认情况下Android中新诞生的线程是没有开启消息循环的(主线程中new的则有)。换句话说,Looper内部有一个线程对象,这个对象会轮询获取消息队列的消息,这个消息队列就是MessageQueue,Looper对象通过MessageQueue来存放消息和事件,一个线程只能有一个Looper,对应一个MessageQueue。

总结就是:

    A:主线程中 handler = new Handler();那么这个handler内部绑定了 Looper.getMainLooper() 对象或Looper.myLooper();

    B:在子线程中,如在Thread中 handler = new Handler();那么这个handler的Looper对象时空的。

那么,关于子线程中应该如何为handler注册Looper呢?可以这样使用

  HandlerThread handlerThread = new HandlerThread("sub thread");

  handlerThread.start(); // 这句很重要 ,应该是为线程异步运行提供环境

  handler = new Handler(handlerThread.getLooper());

2)采用继承方式,继承方式就是多了Looper对象的绑定方法,这样绑定确实有点麻烦。

     class MyHandler extends Handler {
         public MyHandler() {
         }
 
         public MyHandler(Looper looper) {
             super(looper);
         }
 
         // 子类必须重写此方法,接受数据
         @Override
         public void handleMessage(Message msg) {
              // msg.what 进行判断,调用对应的方法更新UI
         }
     }

3)采用内部类方式,内部类方式与默认new Handler相差无几,唯一的区别就是内部类需要重写handleMessage方法,否者意义就不大了,项目中往往使用这种方式。那么为什么推荐这种方式呢?首先我们定义个全局的私有Handler,然后定义时采用内部类实例化对象,下次使用时直接调用handler,只要保证这个handler的Looper对象是主线程的Looper就好,也就是不要在自己的Thread中去实例化handler。


3、handler调用

1)由于一切关于消息队列的事情都有Looper对象处理,那么就不必过于深究了。现在只要好好理解如何使用handler,关于handler同步的问题,如果handler内部绑定的是主线程的Looper对象,那么,在我们调用 handler.post(new Thread())的时候,这个注册的Thread其实是在主线中串行,而不是并行。就好像调用的是Thread对象的run方法而非start方法,那么意义就不大了!

2)项目中耗时的工作应该给一个异步的子线程处理,如果你放在主线程中的话,界面会出现假死现象,,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"。然而子线程又不能更新主线程的UI,那么问题就来了,应该如何结合Handler让子线程与主线程并行呢?一种方式就是采用 handlerThread 为 当前的handler对象绑定一个全新的 Looper对象,那么就可以实现以上要求了。当然,更好的方式是:单独new Thread ,在Thread内部调用已经实例化话好的handler对象,这样也是一个异步调用。


4 handler消息传送

1)Message对象是与handler绑定的,handler可以采用sendMessage(Message)方式把Message对象发送到handler的handleMessage方法中,一般我们采用message.what 方法作为不同消息类型的标识;另外,message的两个参数 arg1 与 arg2 是效率相对较高的,因为他们消耗系统性能较少。

2)Bundle对象是handler的一个成员变量,可以把bundle看成是一个特殊的Map对象,二者都是用来缓存数据,只是Bundle的key只能是String,而且Bundle的方法相对Map更为丰富。另外,Bundle对象不局限与handler,在intent或者在Activity的onCreate方法中处处可见。


总结:

    不能在子线程中直接更新Android UI ,需要采用Handler处理,然而handler处理时需要注意内部的Looper对象是否已经绑定,如果没有绑定需要手动注册一个Looper。对于同步还是异步调用,也需要适当的处理。


© 著作权归作者所有

learn_more
粉丝 93
博文 240
码字总数 210196
作品 0
深圳
程序员
私信 提问
Handler导致内存泄露分析

Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // do something. } } HandlerAndroid Lintwarning: In Android, Handler classes should be st......

子曰疯
2014/08/26
3K
1
android基础知识02——线程安全3:Message,MessageQueue,Handler,Looper

android的UI操作不是线程安全的,同时也只有主线程才能够操作UI,同时主线程对于UI操作有一定的时间限制(最长5秒)。为了能够做一些比较耗时的操作(比如下载、打开大文件等),android提供...

迷途d书童
2012/03/23
775
0
Android线程管理(二)——ActivityThread

上文分析了Handler、MessageQueue、Message及Looper四者的关系,本文将对Android中最重要的线程——ActivityThread进行说明。 二、ActivityThread的主要工作及实现机制 ActivityThread是And...

yhthu
2017/05/18
0
0
android的消息处理机制(图+源码分析)——Looper,Handler,Message

作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类...

火蚁
2014/05/14
229
0
Android的消息处理机制(图+源码分析)——Looper,Handler,Message

作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设 计模式,除此以外,android sdk还精心为我们设计了各种helper类...

Jerikc
2013/12/28
414
0

没有更多内容

加载失败,请刷新页面

加载更多

还为PDF转Word抓狂?以下神器让你在职场倍受欢迎!

身在职场的你,是否一直在琢磨:如何能让自己在公司更受欢迎?如何才能在办公室里混个好人缘?如何在同事圈里留个好印象?其实,想要让自己成为受欢迎的人,只要让自己成为大家需要的人不就行...

foxit2world
10分钟前
4
0
AndServer+Service打造Android服务器实现so文件调用

so 文件调用 随着 Android 移动安全的高速发展,不管是为了执行效率还是程序的安全性等,关键代码下沉 native 层已成为基本操作。 native 层的开发就是通指的 JNI/NDK 开发,通过 JNI 可以实...

夜幕NightTeam
12分钟前
3
0
Docker下kafka学习三部曲之二:本地环境搭建

在上一章《 Docker下kafka学习,三部曲之一:极速体验kafka》中我们快速体验了kafka的消息分发和订阅功能,但是对环境搭建的印象仅仅是执行了几个命令和脚本,本章我们通过实战来学习如何编写...

程序员欣宸
12分钟前
4
0
萌新推荐!不再为Excel转换PDF发愁,Aspose.Cells for .NET一步到位!

Aspose.Cells for .NET(点击下载)是Excel电子表格编程API,可加快电子表格管理和处理任务,支持构建具有生成,修改,转换,呈现和打印电子表格功能的跨平台应用程序。 将Excel工作簿转换为...

mnrssj
13分钟前
6
0
对于绘画小白怎么画制服?该注意什么?

怎样制作学生服装?想必绘画初学者们常常会想的问题吧,不知道怎样才能画好人物的衣服,别着急,今日就在这儿讲一些关于如何绘画学生衣服校服的教程给我们!期望能够帮到你们! 轻便西装是不...

热爱画画的我
18分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部