与多线程结合使用的消息处理类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 消息处理,消息循环从消息队列中取 ...
随机推荐
- CircleIndicator
dependencies { compile 'com.nineoldandroids:library:2.4.+' compile 'me.relex:circleindicator:1.0.0@a ...
- 修改 jupyter notebook 启动工作路径的方法
Windows下jupyter notebook默认的启动路径就是当前cmd启动jupyter 的路径: C:\Users\用户名>jupyter notebook 此时jupyter 的启动工 ...
- int类中的方法
我们知道在python中,一切对象都是类,对象的方法都封装在类中,现在来探讨一下int类中的方法: 我们可以通过help(int)和dir(int)来查看int类中都封装了那些方法: 1.bi ...
- Python函数系列-迭代器,生成器
一 迭代器 一 迭代的概念 #迭代器即迭代的工具,那什么是迭代呢?#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单纯地重复,因而不 ...
- 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 xor (根号分治)
xor There is a tree with nn nodes. For each node, there is an integer value a_iai, (1 \le a_i \le ...
- The dd command of linux
The dd command stands for "data duplicator" and used for copying and converting data. It i ...
- SpringBoot学习(二)
MyBatis是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.spring Boot 是能支持快速创建 Spring 应用的 ...
- Vue 2.0学习(七)方法与事件
基本用法 以监听一个按钮的点击事件为例,设计一个计数器,每次点击都加1: <div id = "app"> 点击次数:{{ counter }} <button ...
- noip2007树网的核
想一下可以发现随便枚举一条直径做就可以了. 核越长越好.于是枚举核的过程可以做到O(n) 然后就是统计答案. 对于每个核最大偏心距肯定是核上面每个点不走核内的点所能走到的最远点的最值. 而且对于核的两 ...
- NOIP200606金明的预算方案
试题描述: 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”. ...