《深入理解Android:Telephony原理剖析与最佳实践》一3.2 Handler消息处理机制

3.2 Handler消息处理机制

Android在设计的时候引入了Handler消息机制,每一个消息发送到主线程的消息队列中,消息队列遵循先进先出原则,发送消息并不会阻塞线程,而接收线程会阻塞线程。我们接着来看看在Android中对Handler是如何定义的?

3.2.1 Handler概念分析

Handler的官方定义如下:
A Handler allows you to send and process Message and Runnable objects associated with a thread抯 MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Handler允许发送并处理Message消息,Message对象通过主线程的MessageQueue消息队列相关联的 Message 和 Runnable 对象进行存取。每个Handler实例对Message消息发送和接收与对应主线程和主线程的消息队列有关。当创建一个新Handler时,Handler就属于当前主线程,主线程的MessageQueue消息队列也同步创建,即Handler会绑定到创建该Handler主线程/消息队列中。然后,Handler就可以通过主线程的消息队列发送和接收Message消息对象了。

3.2.2 Handler特性

1)Android里没有全局Message Queue消息队列,每个Activity主线程都有一个独立的Message Queue消息队列,消息队列采用先进先出原则。不同APK应用不能通过Handler 进行Message通信,同一个APK应用中可通过Handler对象传递而进行Message通信。
2)每个Handler实例都会绑定到创建它的线程中(一般位于主线程,即Activity线程),但Handler实例均可在主线程或子线程中创建。
3)Handler发送消息使用Message Queue消息队列,每个Message发送到消息队列里面,遵循先进先出原则;发送消息采用异步方式不会阻塞线程,而接收线程采用同步方式会阻塞线程,所以当Handler 处理完一个 Message 对象后才会接着去取下一个消息进行处理。

3.2.3 常用Handler消息处理机制讲解

我们根据几种常用Handler消息传递的使用方式用一个实例来对照讲解。
创建一个新Activity,包含4个button按钮,分别是button1、button2、button3和button4,设置它们的onClick点击事件,本例中每个button在响应点击事件中实现不同方式的Handler消息处理机制。
button1:完成主线程中传递Handler消息处理机制。
button2:在子线程中完成Handler消息处理机制。
button3:在其他线程中传入Handler对象并完成其消息处理机制。
button4:一个验证,在其他线程中更新ActivityUI界面会抛出异常。
1. 新建一个Activity
首先,创建一个新Activity,在布局文件中加入button1到button4 4个Button按钮,然后在代码中加入这4个Button的创建及响应onClick事件代码,关键代码如下:

public class AndroidTestActivity extends Activity implements OnClickListener {
  Button button1 = null;
  Button button2 = null;
  Button button3 = null;
  Button button4 = null;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //设置Button的onClick事件
    button1 = (Button)findViewById(R.id.button1);
    button1.setOnClickListener(this);
    ……//button2、button3、button4的创建和设置其点击事件的代码参考button1即可
 }
  //实现OnClickListener接口未实现的onClick方法,此方法响应前面创建的4个Button点击事件
  public void onClick(View v) {
     dealOnClick(v.getId());//进入onClick事件处理
  }
  1. 自定义MyHandler类
    接着,在Activity类中自定义MyHandler类,继承自Handler类,覆盖父类handleMessage方法,并在此方法中实现接收到Handler消息后的处理逻辑,使用Toast显示Handler传递的消息内容,其关键代码如下:

    public class MyHandler extends Handler {
    //重写构造方法可通过Looper创建MyHandler对象
    public MyHandler(Looper myLooper) {
    super(myLooper);
    }
    public MyHandler() {
    }
    //重写handleMessage方法,定义接收到MyHandler对象发送的Message消息后由此方法进行响应
    @Override
    public void handleMessage(Message msg) {
    String str = "";//Toast显示的文本内容
    switch(msg.what){//根据Handler消息的不同消息类型,组合不同的String字符串
    case 1:
    //msg.obj为Message对象传递的Object对象,本例中为String对象
    str = "1:" + msg.obj;
    break;
    ……//省略对Handler消息类型为2和3的代码,读者可结合前面的代码自行加入处理逻辑代码
    }
    //使用str字符串内容构造Toast对象
    Toast toast = Toast.makeText(AndroidTestActivity.this, str, Toast.LENGTH_SHORT);
    toast.show();//Toast显示Handler接收消息
    }
    }

    至此,本例的基本框架已经基本完成。回想一下,从button1到button4共4个按钮的创建及响应onClick事件处理;自定义的MyHandler及handleMessage响应Handler消息处理逻辑;这些都已经完成,还差什么呢?还没有完成在onClick方法中调用的dealOnClick方法处理逻辑,接下来完成dealOnClick方法的处理逻辑。
  2. Handler消息发送和处理方法
    本例中选择三种比较常用的Handler消息发送和处理方法,当然Android Handler的消息发送处理机制不只限于本例的这三种方法,其他的方法留给读者去学习和总结。
    (1)dealOnClick方法加入针对button1点击事件处理逻辑
    在主线程中创建Handler和Message对象,最后Handler发送消息也在主线程中完成,其代码详情如下:

    switch (buttonId) {
    case R.id.button1://button1处理机制
    mHandler = new MyHandler();//主线程中创建自定义MyHandler对象,这里还需要在//AndroidTestActivity类中增加mHandler属性的声明
    // mHandler创建Handler消息类型为1、消息对象为字符串的Message对象
    m = mHandler.obtainMessage(1, (Object)"Main thread send message by Message Object");
    m.sendToTarget();//Handler发送消息
    break;

    回顾button1点击事件的响应逻辑代码,自定义的Handler对象和Message对象均在Activity主线程中创建,Handler发送消息后,在自定义的Handler中handleMessage方法中响应并接收消息。我们可运行此实例验证button1的逻辑是否正确。

注意 MyHandler的构造方法有两种,区别是不带Looper对象和带Looper对象,在这里为什么使用不带Looper对象的构造方法呢?有什么特殊处理吗?既然有Android源代码,我们进去看看就清楚了。
在Eclipse中打开Android 4.0.3源代码工程,接着打开android.os.Handler类,Handler的不带Looper对象的构造方法代码如下:

mLooper = Looper.myLooper();//获取了Looper对象
  if (mLooper == null) {   //我们只能在Activity主线程中使用不带Looper对象的构造方法创建
           //Handler对象,否则获取不了Looper,接着便会抛出RuntimeException的异常
    throw new RuntimeException(
      "Can't create handler inside thread that has not called Looper.prepare()");
  }

(2)dealOnClick方法加入针对button2点击事件处理逻辑
在子线程中异步创建Handler和Message对象,并发送Handler消息,其代码详情如下:

switch (buttonId) {
case R.id.button2:
    InnerMyThread imt = new InnerMyThread();
    imt.start();//内部线程对象异步处理button2事件
    break;

接着完成InnerMyThread的处理逻辑,其代码详情如下:

private class InnerMyThread  extends Thread {
  @Override
  public void run() {
    mHandler = new MyHandler();//仅能在Activity主线程内采用不带Looper对象创建Handler//对象,此处会抛出异常
    mHandler = new MyHandler(Looper.myLooper());//Looper.myLooper获取looper为//null,产生异常
    mHandler = new MyHandler(Looper.getMainLooper());//通过Looper.getMainLooper()//获取父类的looper可成功创建Handler对象并将Message发送到父类
    Message m = mHandler.obtainMessage(2, (Object)"Inner thread send message by Message Object");//子线程中创建Message对象
    m.sendToTarget();//子线程中发送Message
  }
}

回顾button2点击事件的响应逻辑代码,子线程中异步创建Handler和Message对象,并在子线程中发送Handler消息,接着在主线程中的handleMessage方法中响应子线程发出的Handler消息。
(3)dealOnClick方法加入针对button3点击事件处理逻辑
在主线程中创建Handler对象,子线程创建Message消息并发送Handler消息,代码如下:

switch (buttonId) {
case R.id.button3:
mHandler = new MyHandler();
    MyThread mt = new MyThread(mHandler);//传递mHandler对象给子线程
    mt.start();//子线程对象,用于异步处理Handler Message消息
    break;

主线程创建的Handler对象传递给子线程,在子线程中通过Handler对象创建Message对象,并在子线程中发送Handler消息,主线程在handleMessage中响应接收消息。代码如下:

public class MyThread  extends Thread {
    private Handler mHandler;
    public MyThread (Handler mHandler) {
        this.mHandler = mHandler;
    }
    @Override
    public void run() {
        Message m = mHandler.obtainMessage(3, (Object)"Other thread send message by mHandler");
        m.sendToTarget();
    }
}

(4)dealOnClick方法中加入针对button4点击事件处理逻辑
在子线程中更新Activity界面,请读者自己完善代码,验证在子线程中更新主线程的界面究竟会有什么异常出现。

3.2.4 Handler的作用

根据Handler处理Message消息相关特性和前面的实例,可以得出这样的结论:Handler主要作用是异步处理较费时的逻辑,优先将界面返回给用户,异步处理完成后再去更新用户界面。
在Android中当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程专门管理界面中的UI控件,对事件进行分发, 比如点击一个 Button按钮,Android会分发事件到具体的Button按钮上,来响应用户的操作。
如果此时需要一个耗时的操作,例如联网读取数据或者读取本地较大的一个文件,不能把这些操作放在主线程中,放在主线程中的话,界面会出现假死现象, 如果5秒还没有完成,会收到Android系统的一个错误提示“强制关闭”,在这样的情况下需要把这些耗时的操作放入子线程中去处理,子线程处理完成后涉及再去更新主线程的UI界面,而Android主线程是线程不安全的。也就是说,更新UI只能在主线程中更新,子线程中无法更新主线程的界面。
这时,Android设计出Handler来解决这个复杂的问题,由于Handler运行在主线程中(Activity UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接收子线程传过来的Message对象(包含消息标识和数据对象)的责任,从而配合主线程更新UI。而这些消息都通过主线程的消息队列按照先进先出的方式进行发送和接收并做相关处理。

时间: 2024-08-07 02:04:29

《深入理解Android:Telephony原理剖析与最佳实践》一3.2 Handler消息处理机制的相关文章

《深入理解Android:Telephony原理剖析与最佳实践》一第3章 主要技术准备

第3章 主要技术准备 第2章介绍了搭建Android源码编译环境以及Android相关常用工具使用的一些技巧和总结,接下来我们是不是应该开始学习Android Telephony相关内容了呢?先不着急,工欲善其事,必先利其器,我们还要做一些的技术准备工作,也就是学习Android Telephony涉及的一些关键技术,其中包括Handler消息处理机制.AIDL跨应用服务访问和Broadcast系统广播.这些技术在Telephony中使用较多,所以在学习Telephony前,需要对这几个重点技术

《深入理解Android:Telephony原理剖析与最佳实践》一导读

前 言 随着ICT技术的推广和发展,在三网融合.智慧的地球(物联网)等概念风行的形势下,手机终端技术的发展和进步可谓日新月异:Android经受住了市场的考验,并占据了较大的市场份额,从手机芯片厂家.手机生产厂家到各种应用开发公司.互联网公司等,逐步形成了以Android系统平台为核心的上下游产业链.正是由于Android源代码的开源,各大手机厂商才能通过深度定制Android系统平台,在降低研发成本的同时,快速推出具有自身特色的Android智能手机产品.因此,各大手机厂家在推出新版本Andr

《深入理解Android:Telephony原理剖析与最佳实践》一1.3 Android Telephony框架结构

1.3 Android Telephony框架结构 前面对Android手机操作系统整体框架结构及每一层进行了简单的分析和说明,相信大家对Android智能手机操作系统有了一些基本的了解和认识.结合前面Android的系统整体框架,我们接着学习Android Telephony涉及的框架结构,如图1-3所示. 通过图1-3所示不难发现Android Telephony框架结构的一些规律,总结如下. Android Telephony的业务应用跨越了AP和BP.AP与BP相互通信,符合前面介绍的智

《深入理解Android:Telephony原理剖析与最佳实践》一3.5 本章小结

3.5 本章小结 本章主要对Android Telephony相关模块使用到的一些关键技术进行了分析和实例讲解,包括Handler.Broadcast两种异步通信的机制和AIDL跨应用的服务调用.Handler主要有几种消息处理方式?Handler对象的创建在主线程和子线程有什么区别?AIDL如何定义接口?AIDL接口定义完成后,对应的代码是如何生成的?Broadcast接收方的过滤器有几种设置方式?通过本章的学习,相信大家都对这些知识点会有较深入的认识和理解. 对Android中的Handle

《深入理解Android:Telephony原理剖析与最佳实践》一3.3 AIDL跨应用服务

3.3 AIDL跨应用服务 Android Telephony框架层提供了一些AIDL系统服务以及第三方应用,通过这些系统服务可方便地获取手机当前状态,如待机状态.通话中.来电等,这些状态在Android手机应用开发中非常重要.如果我们开发一款Android平台的手机音乐播放器,在使用音乐播放器的过程中需要知道手机当前是什么状态,如果是通话中或来电,这时就必须暂停播放音乐. 3.3.1 AIDL概念分析 什么是AIDL呢?AIDL的Android官方定义如下: AIDL (Android Int

《深入理解Android:Telephony原理剖析与最佳实践》一3.1 何为同步和异步

3.1 何为同步和异步 Android Telephony相关应用中,Telephony大量使用了Handler.Broadcast等通信方式,而在Android操作系统平台中的Handler消息处理.Broadcast广播消息等均采用异步通信机制,那么我们首先要清楚什么是异步通信机制,与它相对同步的通信机制是什么,有什么区别. Synchronous(同步)和Asynchronous(异步)的概念最早来自通信领域. 通信的同步:指客户端在发送请求后,必须要在服务端有回应后客户端才继续发送其他请

《深入理解Android:Telephony原理剖析与最佳实践》一第2章 搭建Android源代码编译环境

第2章 搭建Android源代码编译环境 第1章介绍了Android以及其Telephony功能模块的基本结构,在本章中将带着读者去搭建Android编译环境.即使你已经能够在自己计算机上成功编译Android源代码了,也希望你能阅读本章内容,因为本章不乏一些技巧的总结和Android相关实用工具使用方法的介绍. Android的编译环境作为深入学习Android的基础,不可缺失,能够成功下载Android源代码并编译成功,对深入学习Android是非常关键和重要的一步:Android环境搭建比

《深入理解Android:Telephony原理剖析与最佳实践》一2.1 Ubuntu Linux操作系统及工具安装

2.1 Ubuntu Linux操作系统及工具安装 要搭建Android的编译环境,首先要选择好使用什么操作系统.本书选择Ubuntu 10.10桌面版64位Linux操作系统作为编译Android源码的操作系统. 注意 为什么选择使用64位Ubuntu 10.10桌面版的操作系统呢?在搭建Android源代码编译环境的过程中通过对比Ubuntu 10版本和11版本,发现Ubuntu 10更加简单,比如在Ubuntu 11.10采用的GCC和G++ 4.6版本,需要回退到4.4版本,否则会出现编

《深入理解Android:Telephony原理剖析与最佳实践》一第1章 初识Android

第1章 初识Android Android中文意思为"机器人",中文翻译为"安卓",是Google于2007年11月5日发布的基于Linux平台的开源手机操作系统的名称.该平台由操作系统.中间件.用户界面和应用软件组成,被称为首个为移动终端打造的真正开放和完整的移动软件.Google与电信运营商.手机设备制造商.芯片开发商以及其他有关方面结成深层次的合作伙伴关系,希望借助建立标准化.开放式的移动电话软件平台,在移动产业内形成一个开放式的生态系统. 从2007年到现在