与多线程结合使用的消息处理类Handler、Message
1. 消息处理类——Handler
消息处理类(Handler)允许发送和处理Message或Runnable对象到其所在线程的MessageQueue中。Handerl有以下两个主要作用:
- 将Message或Runnable应用post()方法或sendMessage()方法发送到MessageQueue中,在发送时可以指定延迟时间、发送时间或者要携带的Bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。
- 在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。
说明:在一个线程中,只能有一个Looper和MessageQueue,但是,可以有多个Handler,而且这些Handler可以共享同一个Looper和MessageQueue。
Handler类提供的常用方法
| 方法 | 描述 |
| handleMessage(Message msg) | 处理消息的方法。通常重写该方法来处理消息,在发送消息时,该方法会自动回调。 |
| post(Runnable r) | 立即发送Runnable对象,该Runnable对象最后将被封装成Message对象 |
| postAtTime(Runnable r, long uptimeMillis) | 定时发送Runnable对象,该Runnable对象最后将被封装成Message对象 |
| postDelayed(Runnable r, long delayMillis) |
延迟多少毫秒发送Runnable对象,该Runnable对象最后将被封装成Message对象 |
| sendEmptyMessage(int what) | 发送空消息 |
| sendMessage(Message msg) | 立即发送消息 |
| sendMessageAtTime(Message msg, long uptimeMillis) | 定时发送消息 |
| sendMessageDelayed(Message msg, long delayMillis) | 延迟多少毫秒发送消息 |
2. 消息类——Message
消息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象。每个Message对象可以通过Message.obtain()方法或者Handler.obtainMessage()方法获得。一个Message对象具有下表所示的5个属性。
Message类的属性
| 属性 | 类型 | 描述 |
| arg1 | int | 用来存放整型数据 |
| arg2 | int | 用来存放整型数据 |
| obj | Object | 用来存放发送给接收器的Object类型的任意对象 |
| replyTo | Messenger | 用来指定此Message发送到何处的可选Messager对象 |
| what | int | 用于指定用户自定义的消息代码,这样接收者可以了解这个消息的信息 |
说明:使用Message类的属性可以携带int型的数据,如果要携带其他类型的数据,可以先将要携带的数据保存到Bundle对象中,然后通过Message类的setDate()方法将其添加到Message中。
综上所述,Message类的使用方法比较简单,只要在使用它时,注意以下3点即可:
- 尽管Message有public的默认构造方法,但是通常情况下,需要使用Message.obtain()方法或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源。
- 如果一个Message只需要携带简单的int型信息,应优先使用Message.arg1和Message.arg2属性来传递信息,这比用Bundle更省内存。
- 尽可能使用Message.what来标识信息,以便用不同的方式处理Message。
3. 用Handler和Message实现一个每隔1秒更新时间的程序
1. 布局文件activity_main.xml内容如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
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="com.example.tiaoshi.MainActivity" > <TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="每秒变化的文本" />
<Button
android:id= "@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stop" /> </LinearLayout>
2. MainActivity内容如下
package com.example.tiaoshi; import java.util.Date; import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends ActionBarActivity implements Runnable {
private Button startBtn = null;
private Button stopBtn = null;
private Thread thread = null;
private Handler handler = null;
private TextView text = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.text = (TextView) this.findViewById(R.id.text);
//处理消息
handler = new Handler(){ @Override
public void handleMessage(Message msg) {
if(msg.what==0x101){
text.setText("当前时间为:"+new Date());
}
super.handleMessage(msg);
} };
this.startBtn = (Button) this.findViewById(R.id.btn1);
startBtn.setOnClickListener(new OnClickListener(){ @Override
public void onClick(View arg0) {
thread = new Thread(MainActivity.this);
thread.start();
text.setText("当前时间为:"+new Date());
} });
this.stopBtn = (Button) this.findViewById(R.id.btn2);
stopBtn.setOnClickListener(new OnClickListener(){ @Override
public void onClick(View arg0) {
if(thread!=null){
thread.interrupt();
thread = null;
}
Log.i("提示", "中断线程");
} });
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} @Override
public void run() {
try {
while(!Thread.currentThread().isInterrupted()){
Message m = handler.obtainMessage(); //获取一个空的message
m.what = 0x101; //设置消息标识
handler.sendMessage(m); //发送消息
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } @Override
protected void onDestroy() {
if(thread!=null){
thread.interrupt();
thread = null;
}
super.onDestroy();
}
}
4. 创建Handler对象发送并处理消息
在Eclipse中创建Android项目,创建一个继承了Thread类的LooperThread,并在重写的run()方法中,创建一个Handler对象并处理消息。
在Android中,一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列)。MessageQueue用于存放Message(消息),在MessageQueue中,存放的消息按照FIFO(先进先出)原则执行,由于MessageQueue被封装到Looper里面了,所以这里不对MessageQueue进行过多介绍。
Looper对象用来为一个线程开启一个消息循环,用来操作MessageQueue。默认情况下Android中新创建的线程是没有开启消息循环的。但是主线程除外,系统自动为主线程创建Looper对象,开启消息循环。所以,当我们在主线程中,应用下面的代码创建Handler对象时,就不会出错,而如果在创建的非主线程中,应用下面的代码创建Handler对象时,将产生异常信息。
Handler handler = new Handler();
如果想要在非主线程中,创建Handler对象,首先需要使用Looper类的prepare()方法来初始化一个Looper对象,然后创建这个Handler对象,再使用Looper类的loop()方法启动Looper,从消息队列里获取和处理消息。
Looper类提供的常用方法如下表所示。
| 方法 | 描述 |
| prepare() | 用于初始化Looper |
| loop() | 调用loop()方法后,Looper线程就开始真正工作了,它会从消息队列里获取消息和处理消息 |
| myLooper() | 可以获取当前线程的Looper对象 |
| getThread() | 用于获取Looper对象所属的线程 |
| quit() | 用于结束Looper循环 |
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个循环,当调用Handler.getLooper().quit()方法后,loop()方法才会终止,其后面的代码才能得以执行。
1. 创建一个继承了Thread类的LooperThread,并在重写的run()方法中,创建一个Handler对象发送并处理消息,关键代码如下:
package com.example.tiaoshi; import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log; public class LooperThread extends Thread {
public Handler handler; //声明一个Handler对象
@Override
public void run() {
super.run();
Looper.prepare(); //初始化Looper对象
//实例化一个Handler对象
handler = new Handler(){ @Override
public void handleMessage(Message msg) {
Log.i("Looper", String.valueOf(msg.what));
} };
//获取一个消息
Message m = handler.obtainMessage();
//设置Message的what属性的值
m.what = 0x11;
// 发送消息
handler.sendMessage(m);
//启动Looper
Looper.loop();
} }
2. 在MainActivity的onCreate()方法中,创建一个LooperThread线程,并开启该线程,关键代码如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LooperThread thread = new LooperThread(); //创建一个线程
thread.start(); //开启线程
}
与多线程结合使用的消息处理类Handler、Message的更多相关文章
- Android多线程编程<二>Handler异步消息处理机制之Message
Message(消息): 一. Message的字段: 在Android中,Message作为线程之间(主要是子线程和UI主线程之间)数据交换的载体,通过Handler去传递.它 ...
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
Android是消息驱动的,实现消息驱动有几个要素: 消息的表示:Message 消息队列:MessageQueue 消息循环,用于循环取出消息进行处理:Looper 消息处理,消息循环从消息队列中取 ...
- android的消息处理机制——Looper,Handler,Message
在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...
- (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)
转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...
- Android消息处理机制(Handler 与Message)---01
一.handler的使用场景为么会有handler?(部分内容图片摘自http://www.runoob.com/w3cnote/android-tutorial-handler-message.ht ...
- 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制
PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...
- java多线程并发去调用一个类的静态方法安全性探讨
java多线程并发去调用一个类的静态方法安全性探讨 转自:http://blog.csdn.net/weibin_6388/article/details/50750035 这篇文章主要讲多线程对 ...
- 【Java多线程系列五】列表类
一些列表类及其特性 类 线程安全 Iterator 特性 说明 Vector 是 fail-fast 内部方法用synchronized修饰,因此执行效率较低 1. 线程安全的列表类并不意味着调用它 ...
- Android Handler处理机制 ( 二 ) ——Handler,Message,Looper,MessageQueue
Android是消息驱动的,实现消息驱动有几个要素: 消息的表示:Message 消息队列:MessageQueue 消息循环,用于循环取出消息进行处理:Looper 消息处理,消息循环从消息队列中取 ...
随机推荐
- 在WebClient类中保持Session
string url = context.Request["url"]; WebClient MyWebClient = new WebClient(); // 获取或设置用于向I ...
- [实战]MVC5+EF6+MySql企业网盘实战(6)——ajax方式登录
写在前面 今天回来的比较早,就趁着有空,把登录的代码更新一下.上篇文章实现了ajax的注册,这篇将实现登录,实现目标,ajax登录方式,如果勾选记住我,则下次不再输入用户名密码,直接跳转到网盘界面. ...
- 尝试php命令行脚本多进程并发执行
php不支持多线程,但是我们可以把问题转换成“多进程”来解决.由于php中的pcntl_fork只有unix平台才可以使用,所以本文尝试使用popen来替代. 下面是一个例子: 被并行调用的子程序 ...
- JAVA编程思想读书笔记(三)--RTTI
接上篇JAVA编程思想读书笔记(二) 第十一章 运行期类型判定 No1: 对于作为程序一部分的每个类,它们都有一个Class对象.换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当的说, ...
- Django实现单用户登录
最近由于要毕业了写论文做毕设,然后还在实习发现已经好久都没有写博客了.今天由于工作需求,需要用Django实现单用户登录.大概意思就是跟QQ一样的效果,每个账号只能一个地方登录使用,限制账号的登录次数 ...
- XV6操作系统代码阅读心得(二):进程
1. 进程的基本概念 从抽象的意义来说,进程是指一个正在运行的程序的实例,而线程是一个CPU指令执行流的最小单位.进程是操作系统资源分配的最小单位,线程是操作系统中调度的最小单位.从实现的角度上讲,X ...
- python __str__ , __repr__区别
Python 有办法将任意值转为字符串:将它传入repr() 或str() 函数. 函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式 (如果没有等价的语法,则会 ...
- WebLogic Server
前几天,看了几集J2ee , 给我的感觉就是,看不懂!! 一点也不懂! 那怎么办呢? 听老师的,不管懂不懂,先看看再说.接下来,就开始了J2ee "艰苦"的历程.在J2ee中,经常 ...
- 关于那些oj链接
luogu codeforces bzoj poj tyvj
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1360 Solved: 545[S ...