参考《疯狂android讲义》第2版3.5 P214

一、背景

出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的原则:只允许UI线程(亦即主线程)修改Activity中的UI组件。

当一个程序第一次启动时,Android会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件、屏幕绘图事件,并把相关的事件分发到相应的组件进行处理,所以主线程通常又叫做UI线程。

二、使用Handler的两种常见原因

1、只能在主UI中修改UI。但实际上,有部分UI需要在子线程中控制其修改逻辑,因此子线程需要通过handler通知主线程修改UI。这在游戏开发中尤其常见,比如需要让新启动的线程周期性的改变UI。

2、为避免ANR,应该在子线程中执行耗时较长的操作,而此操作完成后,有可能需要通知主线程修改UI。

三、基本原理及步骤

1、Handler的作用主要有2个:

(1)发送消息。

(2)获取、处理消息。

2、基本原理:为了让主线程能及时处理子线程发送的消息,显然只能通过回调的方法来实现----开发者只要重写Handler类中的方法,当新启动的线程发送消息时,消息会发送至与之关联的MessageQueue,而Handler会不断的从MessageQuere中获取并处理消息-----这将导致Handler类中处理消息的方法被回调。

3、在线程中使用Handler的基本步骤如下:

在被调用线程中完成以下内容:

(1)调用 Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。

(2)有了Looper之后,创建Handler子类的实例,重写HandlerMessage()方法,该方法负责处理来自其它线程的消息。

(3)调用Looper的loop()方法启动Looper。

注:若被调用线程是主线程类,由于系统自动为主线程创建了Looper的实例,因此第一、三步骤可省略,而只需要做第2步即可。

在调用线程中完成:

(1)创建nessage,并填充内容。

(2)使用被调用类创建的Handler实例,调用sendMessage(Message msg)方法。

四、实例

1、主线程接收数据,并将之发送至子线程中完成一些耗时操作

package com.ljh.handlerdemo1;import java.util.ArrayList;
import java.util.List;import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends Activity {private final String UPPER_NUMBER = "upper";private CalThread calThread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);calThread = new CalThread();Thread t = new Thread(calThread);t.start();}public void cal(View v) {EditText et_digit = (EditText) findViewById(R.id.et_digit);Message msg = new Message();msg.what = 0x1233;Bundle bundle = new Bundle();bundle.putInt(UPPER_NUMBER,Integer.parseInt(et_digit.getText().toString()));msg.setData(bundle);calThread.handler.sendMessage(msg);}class CalThread implements Runnable {public Handler handler;@Overridepublic void run() {//1、调用 Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueueLooper.prepare();handler = new Handler() {// 2、有了Looper之后,创建Handler子类的实例,重写HandlerMessage()方法,该方法负责处理来自其它线程的消息。@Overridepublic void handleMessage(Message msg){if(msg.what == 0x1233){int upper = msg.getData().getInt(UPPER_NUMBER);List<Integer> nums = new ArrayList<Integer>();// 计算从2开始、到upper的所有质数outer:for (int i = 2 ; i <= upper ; i++){// 用i处于从2开始、到i的平方根的所有数for (int j = 2 ; j <= Math.sqrt(i) ; j++){// 如果可以整除,表明这个数不是质数if(i != 2 && i % j == 0){continue outer;}}nums.add(i);}// 使用Toast显示统计出来的所有质数Toast.makeText(MainActivity.this , nums.toString(), Toast.LENGTH_LONG).show();}}};//调用Looper的loop()方法启动Looper。Looper.loop();}
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><EditTextandroid:id="@+id/et_digit"android:layout_width="wrap_content"android:layout_height="wrap_content"android:hint="@string/limit" /><Button android:id="@+id/bt_prime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/cal"android:onClick="cal"android:layout_below="@id/et_digit" /></RelativeLayout>

参考归档代码HandlerDemo1

2、在主线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可。

package org.crazyit.event;import java.util.Timer;
import java.util.TimerTask;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;/*** Description:* <br/>site: <a href="http://www.crazyit.org">crazyit.org</a>* <br/>Copyright (C), 2001-2014, Yeeku.H.Lee* <br/>This program is protected by copyright laws.* <br/>Program Name:* <br/>Date:* @author  Yeeku.H.Lee kongyeeku@163.com* @version  1.0*/
public class HandlerTest extends Activity
{// 定义周期性显示的图片的IDint[] imageIds = new int[]{R.drawable.java,R.drawable.ee,R.drawable.ajax,R.drawable.xml,R.drawable.classic};int currentImageId = 0;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);final ImageView show = (ImageView) findViewById(R.id.show);final Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg){// 如果该消息是本程序所发送的if (msg.what == 0x1233){// 动态地修改所显示的图片show.setImageResource(imageIds[currentImageId++% imageIds.length]);}}};// 定义一个计时器,让该计时器周期性地执行指定任务new Timer().schedule(new TimerTask(){@Overridepublic void run(){// 发送空消息myHandler.sendEmptyMessage(0x1233);}}, 0, 1200);}
}

Android中的消息机制:Handler消息传递机制相关推荐

  1. Android中Handler消息传递机制应用之子线程不允许操作主线程的组件

    场景 进程 一个Android应用就是一个一个进程,每个应用在各自的进程中运行. 线程 比进程更小的独立运行的基本单位,一个进程可以包含多个线程. 要求 一个TextView和一个Button,点击B ...

  2. 【Android开发】线程与消息处理-Handler消息传递机制之Looper

    在前面已经介绍了在Android中如何创建.开启.休眠和中断线程.不过,此时并没有在新创建的子线程中对UI界面上的内容进行操作,如果应用前面介绍的方法对UI界面进行操作,将抛出异常. 为此,Andro ...

  3. 浅析Android中的消息机制

    在分析Android消息机制之前,我们先来看一段代码: [java] view plaincopy public class MainActivity extends Activity impleme ...

  4. Android中的消息机制

    Android 中的消息机制其实就是指的是 Handler 消息机制以及附带的 Looper 和 MessageQueue 的工作流程. 1.Android 为什么提供Handler? 解决子线程不能 ...

  5. 重温Android中的消息机制

    引入: 提到Android中的消息机制,大家应该都不陌生,我们在开发中不可避免的要和它打交道.从我们开发的角度来看,Handler是Android消息机制的上层接口.我们在平时的开发中只需要和Hand ...

  6. Android开发:图文分析 Handler通信机制 的工作原理

    前言 在Android开发的多线程应用场景中,Handler机制十分常用 下面,将图文详解 Handler机制 的工作原理 目录 1. 定义 一套 Android 消息传递机制 2. 作用 在多线程的 ...

  7. Android中的消息推送

    转载于Android中的消息推送 前段时间做了一个应用,需要用到服务器端向Android或者是Iphone终端主动发送命令.随后客户端做出相应的反应.当时没有找到最佳的方案,一直搁置着.今天看到网上有 ...

  8. Android Handler消息传递机制

    Android中只允许UI线程(也就是主线程)修改Activity里的UI组件.实际开发中,新启动的线程需要周期性地改变界面组件的属性值就需要借助Handler的消息传递机制. Handler类 Ha ...

  9. android handler 传递对象,Android之Handler消息传递机制详解

    前言 在Android开发中,多线程应用是非常频繁的,其中Handler机制随处可见. 下面就本人对Handle的一些理解与大家一起分享,共同回顾下Handle异步消息传递机制. 1.Handler是 ...

最新文章

  1. asp.net ajax学习系列功能强大的UpdatePanel控件
  2. c++ mysql 取出数据,c++从数据库的表中读取数据
  3. 详解:UML类图符号、各种关系说明以及举例
  4. C# webbrowser控件点击页面按钮
  5. Oracle 11g 安装后续——开发工具篇
  6. (译)在Objective-c里面使用property教程
  7. DevExpress.XtraGrid.view.gridview 属性说明
  8. gc日志一般关注什么_JVM(23)JVM的Full GC日志
  9. Python计算从n个元素中任选i个的组合数C(n,i)
  10. Visual Studio Tip 之 如何查看隐形的空格(white space)和制表符(tab)
  11. OkHttp 官方Wiki之【使用案例】
  12. 百度文库付费文档免费下载
  13. NXP JN5169使用硬件SPI读写NRF24L01
  14. 论文阅读:Aspect-based Sentiment Classification with Aspect-specific Graph Convolutional Networks
  15. 数据分析 | 多元线性回归
  16. 搜狗推微信公众平台搜索 可搜公众号与文章
  17. 技术债务管理_管理技术债务
  18. 常用的局域网的网络拓扑有哪些种类?现在最流行的是哪种结构?为什么早期的以太网选择总线拓扑结构而不是星形拓扑结构,但现在却改为使用星形拓扑结构?
  19. 推荐系统中的Embedding应用
  20. 屏蔽win10中文输入法

热门文章

  1. mem库系列函数合集(memset、memchr、memcmp、memcpy)
  2. Python程序开发——第九章 异常处理
  3. kali如何取得超级用户权限_如何在 Ubuntu 上为用户授予和移除 sudo 权限 | Linux 中国...
  4. 安卓期末作品小项目_每日一个财务小知识——洞悉洞晰财务报告第一季
  5. pythonalert弹窗_python+selenium八:Alert弹窗
  6. 全连接条件随机场_CRF条件随机场
  7. miniGUI安装笔记(转)
  8. python的进阶之路_Python 从入门到进阶之路(三)
  9. sh执行文件 参数传递_sh 脚本执行sql文件传参数
  10. python根据坐标点画线_拖动鼠标绘制一条线,并在opencv中获得线端点的坐标Python...