与多线程结合使用的消息处理类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 消息处理,消息循环从消息队列中取 ...
随机推荐
- 猜数字游戏的提示(UVa340)
题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...
- 七 oracle 表查询二
1.使用逻辑操作符号问题:查询工资高于500或者是岗位为manager的雇员,同时还要满足他们的姓名首字母为大写的J?select * from emp where (sal > 500 or ...
- VMware虚拟机VMware Authorization Service不能启动问题
出现VMware Authorization Service不能启动问题,注意要在安装VMware Player时使用管理员权限
- IP地址输入框
<style> div.IPDiv{background:#ffffff;width:120;font-size:9pt;text-align:center;border:2 ridge ...
- NEO4j简单入门
Neo4j是: 一个开源 无Schema 没有SQL 图形数据库 图形数据库也称为图形数据库管理系统或GDBMS. Neo4j的官方网站:http://www.neo4j.org Neo4j的优点 它 ...
- 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)
4665: 小w的喜糖 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 94 Solved: 53 Description 废话不多说,反正小w要发喜 ...
- 【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络
[题目大意] 在一棵有n个节点的树上建信号塔,每个节点的信号塔可以覆盖当前节点极其相连的节点.问要覆盖所有节点,至少需要多少座信号塔? [思路] 经典的树形DP,直接复制一下. f[i][0]:以i为 ...
- 【树上主席树】BZOJ2588-Count on a tree
[题目大意] 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第 ...
- Java并发(二):Java内存模型
一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...
- 零配置文件搭建SpringMvc
零配置文件搭建SpringMvc SpringMvc 流程原理 (1)用户发送请求至前端控制器DispatcherServlet:(2) DispatcherServlet收到请求后,调用Handle ...