1. 消息处理类——Handler 

  消息处理类(Handler)允许发送和处理Message或Runnable对象到其所在线程的MessageQueue中。Handerl有以下两个主要作用:

  1. 将Message或Runnable应用post()方法或sendMessage()方法发送到MessageQueue中,在发送时可以指定延迟时间、发送时间或者要携带的Bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。
  2. 在子线程中与主线程进行通信,也就是在工作线程中与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的更多相关文章

  1. Android多线程编程<二>Handler异步消息处理机制之Message

      Message(消息):       一. Message的字段:    在Android中,Message作为线程之间(主要是子线程和UI主线程之间)数据交换的载体,通过Handler去传递.它 ...

  2. Android消息处理机制(Handler、Looper、MessageQueue与Message)

    Android是消息驱动的,实现消息驱动有几个要素: 消息的表示:Message 消息队列:MessageQueue 消息循环,用于循环取出消息进行处理:Looper 消息处理,消息循环从消息队列中取 ...

  3. android的消息处理机制——Looper,Handler,Message

    在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...

  4. (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)

    转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...

  5. Android消息处理机制(Handler 与Message)---01

    一.handler的使用场景为么会有handler?(部分内容图片摘自http://www.runoob.com/w3cnote/android-tutorial-handler-message.ht ...

  6. 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

    PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...

  7. java多线程并发去调用一个类的静态方法安全性探讨

    java多线程并发去调用一个类的静态方法安全性探讨 转自:http://blog.csdn.net/weibin_6388/article/details/50750035   这篇文章主要讲多线程对 ...

  8. 【Java多线程系列五】列表类

    一些列表类及其特性  类 线程安全 Iterator 特性 说明 Vector 是 fail-fast 内部方法用synchronized修饰,因此执行效率较低 1. 线程安全的列表类并不意味着调用它 ...

  9. Android Handler处理机制 ( 二 ) ——Handler,Message,Looper,MessageQueue

    Android是消息驱动的,实现消息驱动有几个要素: 消息的表示:Message 消息队列:MessageQueue 消息循环,用于循环取出消息进行处理:Looper 消息处理,消息循环从消息队列中取 ...

随机推荐

  1. 猜数字游戏的提示(UVa340)

    题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...

  2. 七 oracle 表查询二

    1.使用逻辑操作符号问题:查询工资高于500或者是岗位为manager的雇员,同时还要满足他们的姓名首字母为大写的J?select * from emp where (sal > 500 or ...

  3. VMware虚拟机VMware Authorization Service不能启动问题

    出现VMware Authorization Service不能启动问题,注意要在安装VMware Player时使用管理员权限

  4. IP地址输入框

    <style> div.IPDiv{background:#ffffff;width:120;font-size:9pt;text-align:center;border:2 ridge ...

  5. NEO4j简单入门

    Neo4j是: 一个开源 无Schema 没有SQL 图形数据库 图形数据库也称为图形数据库管理系统或GDBMS. Neo4j的官方网站:http://www.neo4j.org Neo4j的优点 它 ...

  6. 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)

    4665: 小w的喜糖 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 94  Solved: 53 Description 废话不多说,反正小w要发喜 ...

  7. 【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络

    [题目大意] 在一棵有n个节点的树上建信号塔,每个节点的信号塔可以覆盖当前节点极其相连的节点.问要覆盖所有节点,至少需要多少座信号塔? [思路] 经典的树形DP,直接复制一下. f[i][0]:以i为 ...

  8. 【树上主席树】BZOJ2588-Count on a tree

    [题目大意] 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第 ...

  9. Java并发(二):Java内存模型

    一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...

  10. 零配置文件搭建SpringMvc

    零配置文件搭建SpringMvc SpringMvc 流程原理 (1)用户发送请求至前端控制器DispatcherServlet:(2) DispatcherServlet收到请求后,调用Handle ...