Android 第十四课——Handler Looper Message

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。对于同步还是异步调用,也需要适当的处理。

时间: 2024-08-24 09:15:59

Android 第十四课——Handler Looper Message的相关文章

Android异步消息处理 Handler Looper Message关系源码分析

# 标签: 读博客 对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖. 一.概念.. Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念. 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handle

Android异步处理三:Handler+Looper+MessageQueue深入详解

Android Loop&Handle学习总结 - New Start - 博客频道 - CSDN.NET ?????? 昨晚偷懒,这篇博客只写了一个标题,今天早晨一看,还有15的阅读量.实在是对不起那些同学.......换了是我,也会BS这样的LZ吧!sorry 啦 -------------------------------------------------------------------------------------------------------------------

NeHe OpenGL教程 第四十四课:3D光晕

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十四课:3D光晕 3D 光晕 当镜头对准太阳的时候就会出现这种效果,模拟它非常的简单,一点数学和纹理贴图就够了.好好看看吧. 大家好,欢迎来到新的一课,在这一课中我们将扩展glCamera类,来实现镜头光晕的效果.在日常生活中,

NeHe OpenGL教程 第十四课:图形字体

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第十四课:图形字体 图形字体: 在一课我们将教你绘制3D的图形字体,它们可像一般的3D模型一样被变换. 这节课继续上一节课课的内容.在第13课我们学习了如何使用位图字体,这节课,我们将学习如何使用轮廓字体. 创建轮廓字体的方法类似于

Kali Linux Web 渗透测试视频教程—第十四课-arp欺骗、嗅探、dns欺骗、session劫持

Kali Linux Web 渗透测试视频教程—第十四课-arp欺骗.嗅探.dns欺骗.session劫持 文/玄魂 目录 Kali Linux Web 渗透测试—第十四课-arp欺骗.嗅探.dns欺骗.session劫持      1 关于嗅探.arp欺骗.会话劫持.............................................................. 1 视频教程地址:http://edu.51cto.com/course/course_id-1887.h

第二十四课:能量和功率

1.RC电路充电过程的能量特性: 电源提供的能量  Vs i 在T内积分 如果T远远大于时间常数,则该能量等于 CVs2 但是电容储存的能量等于 (1/2) CVs2 因此一半能量被电阻消耗,另一半则被电容储存起来 2.RC电路放电过程的能量特性: 所以能量消耗在电阻上 3.将两个过程相连,则电源消耗CVs2,一般在充电时消耗,一般在放电时消耗 因此平均功率等于 CVs2f   ,f是充放电的切换频率,愈大功率越大 4.类似于MODFET反相电路 两种功率之和:待机功率和动态功率,后者就是充放电

第三十四课 二维数组的存储 【项目1-3】

第三十四课 二维数组的存储 项目一[二维数组当函数参数] 定义一个函数来完成对参数数组中元素的求和工作,函数声明如下: [cpp] view plain copy print? int sum(int array[ ][4],int m,int n);  //该函数完成对array数组中的前m行和n列元素求和 在以下程序的基础上,完成对sum函数的定义. [cpp] view plain copy print? #include <stdio.h> int sum(int array[ ][4

OpenGL教程翻译 第十四课 相机控制(一)

OpenGL教程翻译 第十四课 相机控制(一) 原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载) Background 在之前的教程中我们学习了如何在三维场景中的任何地方放置相机.那么我们下一步就应该学着去控制这个相机.相机可以向任何方向自由移动.我们可以用鼠标和键盘控制相机--鼠标控制视口方向,键盘控制我们的位置.这些都和第一人称视角相似.这一章我们主要来学习鼠标和键盘的控制. 我们仍然使用上下左右四个方向键.记住,我们的相机的变换取决于位置.targ

Android 基础总结:( 十四)Handler详解(上)

Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发,比如说,你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作. 如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收