Android Handler 消息处理使用
本文内容
- 环境
- 演示 Handler 消息处理
- 参考资料
Handler 有两个主要作用或者说是步骤:发送消息和处理消息。在新启动的线程中发送消息,在主线程中获取、并处理消息。Android 平台只允许UI线程修改 Activity 里的UI组件。
本文只给出核心代码,如果你是初学者,可以下载本文后面的源代码。
环境
- Windows 2008 R2 64 位
- Eclipse ADT V22.6.2,Android 4.4.3
- 三星 SM-G3508,Android OS 4.1
演示 Handler 消息处理
演示主程序如下图 1 所示,有 4 个演示。
图 1 主程序
主程序 XML 页面,只是四个按钮,并为它们添加相应事件,显示 4 个演示的 Activity 而已,略,核心代码如下所示:
- public class MainActivity extends Activity {
- Handler handler = new Handler();
- Intent intent = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- intent = new Intent(MainActivity.this, Handler1Demo.class);
- startActivity(intent);
- }
- });
- findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- intent = new Intent(MainActivity.this, Handler2Demo.class);
- startActivity(intent);
- }
- });
- findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- intent = new Intent(MainActivity.this, Handler3Demo.class);
- startActivity(intent);
- }
- });
- findViewById(R.id.btn4).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- intent = new Intent(MainActivity.this, Handler4Demo.class);
- startActivity(intent);
- }
- });
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
加入和移除 Handler 到主线程
“加入”和“移除” Handler 到主线程,点击“开始”时,每隔1秒,将 Handler 加入到主线程队列中,执行 Runnable 中 run 方法内的代码,显示当前时间;点击“结束”时,从主线程队列移除 Handler。
图 2 加入和移除 Handler 到主线程
XML 页面包含三个组件:两个 Button,一个 TextView(TextView 在 ScrollView 内),略,核心代码如下所示:
- public class Handler1Demo extends Activity {
- private TextView tv = null;
- private Button start = null;
- private Button end = null;
- Handler handler = new Handler();
- // 线程每次执行时,输出时间,延时1秒加入主线程队列
- Runnable r = new Runnable() {
- public void run() {
- tv.append(new Date().toLocaleString() + "\r\n");
- handler.postDelayed(r, 1000);
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.handler_1_demo);
- tv = (TextView) findViewById(R.id.text_view);
- start = (Button) findViewById(R.id.start);
- end = (Button) findViewById(R.id.end);
- // 开始 将handler加入到主线程队列中
- start.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- handler.post(r);
- }
- });
- // 结束 从主线程队列中移除handler
- end.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- handler.removeCallbacks(r);
- }
- });
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
定时 Handler
利用 Timer、TimerTask 和 Handler 定时刷新时间。
图 3 定时 Handler
XML 页面文件略,核心代码如下所示:
- public class Handler2Demo extends Activity {
- private TextView tv = null;
- Timer timer = new Timer();
- Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case 1:
- // 处理消息
- tv = (TextView) findViewById(R.id.text_view);
- tv.append(new Date().toLocaleString() + "\r\n");
- break;
- }
- super.handleMessage(msg);
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.handler_2_demo);
- timer.schedule(new TimerTask() {
- public void run() {
- Message message = new Message();
- message.what = 1;
- handler.sendMessage(message);
- }
- }, 0, 1000);
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
播放动画
跟前一个示例类似。
图 4 播放动画
XML 页面文件略,核心代码如下所示:
- public class Handler3Demo extends Activity {
- // 定义周期性显示的图片的ID
- int[] imageIds = new int[] { R.drawable.java, R.drawable.ee,
- R.drawable.ajax, R.drawable.xml, R.drawable.classic };
- int currentImageId = 0;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.handler_3_demo);
- final ImageView show = (ImageView) findViewById(R.id.show);
- final Handler myHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // 如果该消息是本程序所发送的
- if (msg.what == 0x1233) {
- // 动态地修改所显示的图片
- show.setImageResource(imageIds[currentImageId++
- % imageIds.length]);
- }
- }
- };
- // 定义一个计时器,让该计时器周期性地执行指定任务
- new Timer().schedule(new TimerTask() {
- @Override
- public void run() {
- // 发送空消息
- myHandler.sendEmptyMessage(0x1233);
- }
- }, 0, 1200);
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
计算质数
这个一个更复杂的 Handler。计算从 2 开始,到你指定数之间的所有质数,并用 Toast 显示出来。
Handler 涉及如下几个组件:Message、Looper 和 MessageQueue。
- Looper:每个线程只有一个 Looper,它负责管理 MessageQueue,不断从 MessageQueue 中取出消息,并将消息分给对应的 Handler 处理。
- MessageQueue:由 Looper 负责管理。采用先进先出的方式管理 Message。
- Handler:它能把消息发给 Looper 管理的 MessageQueue,并负责处理 Looper 分给它的消息。
图 5 计算质数
XML 页面文件略,核心代码如下所示:
- public class Handler4Demo extends Activity {
- static final String UPPER_NUM = "upper";
- EditText etNum;
- CalThread calThread;
- // 定义一个线程类
- class CalThread extends Thread {
- public Handler mHandler;
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- // 定义处理消息的方法
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == 0x123) {
- int upper = msg.getData().getInt(UPPER_NUM);
- 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(Handler4Demo.this, nums.toString(),
- Toast.LENGTH_LONG).show();
- }
- }
- };
- Looper.loop();
- }
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.handler_4_demo);
- etNum = (EditText) findViewById(R.id.etNum);
- calThread = new CalThread();
- // 启动新线程
- calThread.start();
- }
- // 为按钮的点击事件提供事件处理函数
- public void cal(View source) {
- // 创建消息
- Message msg = new Message();
- msg.what = 0x123;
- Bundle bundle = new Bundle();
- bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));
- msg.setData(bundle);
- // 向新线程中的Handler发送消息
- calThread.mHandler.sendMessage(msg);
- }
- }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
在新线程内创建了一个 Handler,由于在新线程中创建 Handler 时必须先创建 Looper,因此程序先调用 Looper.prepare() 方法为当前线程创建了一个 Looper实例,并创建配套的MessageQueue,新线程有了 Looper 对象后,接下来创建了一个Handler对象,该 Handler 可以处理其他线程发送过来的消息。程序最后调用了 Looper.loop() 的启动方法。
参考资料
Android Handler 消息处理使用的更多相关文章
- Android Handler消息处理顺序分析
看到Handler中的消息处理函数: public void dispatchMessage(Message msg){...} 这个函数是在Looper的执行消息循环loop()的时候取出Messa ...
- android的消息处理机制——Looper,Handler,Message
在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...
- Android的消息处理机制Looper,Handler,Message
android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...
- android的消息处理有三个核心类:Looper,Handler和Message。
android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为 一名android程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设 ...
- 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...
- 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...
- 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message
原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...
- Android应用开发学习笔记之多线程与Handler消息处理机制
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 和JAVA一样,Android下我们可以通过创建一个Thread对象实现多线程.Thread类有多个构造函数,一般通 ...
随机推荐
- 用C扩展Python3
官方文档: https://docs.python.org/3/extending/index.html 交叉编译到aarch64上面 以交叉编译到aarch64上面为例,下面是Extest.c的实现 ...
- eclipse 安装 weblogic server
- 在Android工程中加入AIDL文件时,gen目录生成的文件报错-问题解决
from://http://blog.csdn.net/watt520/article/details/10099047 今天在弄清除缓存的东东,按照网上别人的方法,创建了一个AIDL文件,这个时候发 ...
- C++ 继承体系中的名称覆盖
首先一个简单的样例: int x; int f() { double x; cin >> x; return x; } 在上述代码中.函数f的局部变量x掩盖了全局变量x.这得从 " ...
- 绝命毒师第一季/全集Breaking Bad迅雷下载
本季Breaking Bad Season 1(2008)看点:新墨西哥州的高中化学老师沃尔特·H·怀特(布莱恩·科兰斯顿 Bryan Cranston 饰)是拮据家庭的唯一经济来源.他大半生安分守己 ...
- Android之sqlite3命令行简单使用
首先需要定位到database所在的目录里面,然后使用命令 sqlite3 databasename(数据库的名字)进入 常用命令: 1. .table 列取该数据库下面的数据表名 2. .s ...
- [Web 前端] 如何在React中做Ajax 请求?
cp from : https://segmentfault.com/a/1190000007564792 如何在React中做Ajax 请求? 首先:React本身没有独有的获取数据的方式.实际上, ...
- Android日志监听工具logcat命令详解(转)
Android日志系统提供了记录和查看系统调试信息的功能.日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过logcat命令来查看和使用. 在使用logcat之前,请确保手机的USB调试 ...
- const 变量修饰 研究
#include<stdio.h> #include<iostream> using namespace std; struct A { ;} ;} }; int main() ...
- verilog语法实例学习(6)
函数和任务 函数 https://wenku.baidu.com/view/d31d1ba8dd3383c4bb4cd283.html verilog中函数的目的是允许代码写成模块的方式而不是定义独立 ...