使用Handler的大致流程:
1、首先创建一个Handler对象,可以直接使用Handler无参构造函数创建Handler对象,也可以继承Handler类,重写handleMessage方法来创建Handler对象。
2、在监听器中,调用Handler的post方法,将要执行的线程对象添加到线程队列当中。此时将会把该线程对象添加到handler对象的线程队列中。
3、将要执行的操作写在线程对象的run方法中,一般是一个Runnable对象,复写其中的run方法就可以了。
Handler包含了两个队列,其中一个是线程队列,另外一个是消息队列。使用post方法会将线程对象放到该handler的线程队列中,使用sendMessage(Message message)将消息放到消息队列中。
如果想要这个流程一直执行的话,可以在run方法内部执行postDelayed或者post方法,再将该线程对象添加到消息队列中,重复执行。想要线程停止执行,调用Handler对象的removeCallbacks(Runnable r) 方法从线程队列中移除线程对象,使线程停止执行。
Handler为Android 提供了一种异步消息处理机制,当向消息队列中发送消息 (sendMessage)后就立即返回,而从消息队列中读取消息时会阻塞,其中从消息队列中读取消息时会执行Handler中的public void handleMessage(Message msg) 方法,因此在创建Handler时应该使用匿名内部类重写该方法,在该方法中写上读取到消息后的操作,使用Handler的 obtainMessage() 来获得消息对象。
Handler与线程的关系:
使用Handler的post方法将Runnable对象放到Handler的线程队列中后,该Runnable的执行其实并未单独开启线程,而是仍然在当前Activity线程中执行的,Handler只是调用了Runnable对象的run方法。
Bundle是什么:
Bundle是一个特殊的map,它是传递信息的工具,它的键只能是string类型,而且值也只能是常见的基本数据类型。
如何让Handler执行Runnable时打开新的线程:
1、首先生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序 框架提供
HandlerThread handlerThread = new HandlerThread("handler_thread");
2、在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
handlerThread.start();
3、根据这个HandlerThread对象得到其中的Looper对象。4、创建自定义的继承于Handler类的子类,其中实现一个参数为Looper对象的构造方法,方法内容调用父类的构造函数即可。
5、使用第三步得到的Looper对象创建自定义的Handler子类的对象,再将消息(Message)发送到该Handler的消息队列中,Handler复写的handleMessage()将会执行来处理消息队列中的消息。
消息,即Message对象,可以传递一些信息,可以使用arg1.arg2,Object传递一些整形或者对象,还可以使用Message对象的 setData(Bundle bundle)来讲Bundle对象传递给新创建的线程,新创建的线程在执行handleMessage(Message msg)时可以从message中利用getData()提取出Bundle对象来进行处理。
view sourceprint?
01 public class HandlerTest2 extends Activity {
02 @Override
03 protected void onCreate(Bundle savedInstanceState) {
04 stub
05 super.onCreate(savedInstanceState);
06 setContentView(R.layout.main);
07 //打印了当前线程的ID
08 System.out.println("Activity-->" + Thread.currentThread().getId());
09 //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序框架提供
10 HandlerThread handlerThread = new HandlerThread("handler_thread");
11 //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
12 handlerThread.start();
13 MyHandler myHandler = new MyHandler(handlerThread.getLooper());
14 Message msg = myHandler.obtainMessage();
15 //将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
16 Bundle b = new Bundle();
17 b.putInt("age", 20);
18 b.putString("name", "Jhon");
19 msg.setData(b);
20 msg.sendToTarget();
21 }
22 class MyHandler extends Handler{
24 public MyHandler(){
25
26 }
27 public MyHandler(Looper looper){
28 super(looper);
29 }
30 @Override
31 public void handleMessage(Message msg) {
32 Bundle b = msg.getData();
33 int age = b.getInt("age");
34 String name = b.getString("name");
35 System.out.println("age is " + age + ", name is" + name);
36 System.out.println("Handler--->" + Thread.currentThread().getId());
37 System.out.println("handlerMessage");
38 }
39 }
40 }
最新历史版本 :Android Handler详解
Java代码
/***
* Handler的定义:
* 主要接受子线程发送的数据, 并用此数据配合主线程更新UI。当应用程序启动时,
* Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说,
* 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。
* 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,
* 如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"。
* 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,
* 也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就出现了,来解决这个复杂的问题 ,
* 由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,
* 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象(里面包含数据),把这些消息放入主线程队列中,配合主线程进行更新UI。
* Handler一些特点:
* Handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
* 它有两个作用: (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
* Handler中分发消息的一些方法
* post(Runnable)
* postAtTime(Runnable,long)
* postDelayed(Runnable,long)
* sendEmptyMessage(int)
* sendMessage(Message)
* sendMessageAtTime(Message,long)
* sendMessageDelayed(Message,long)
* 以上post类方法允许你排列一个Runnable对象到主线程队列中,当需要在不同于主UI线程中执行则需要配合HandlerThread进行使用:
* HandlerThread handlerThread = new HandlerThread("myHandlerThread");
* handlerThread.start();
* handler = new Handler(handlerThread.getLooper());* sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
* @author xiaoshuang
*
*/
public class HandlerActivity extends Activity {
private TextView textView;
private MyHandler myHandler;
private Button button;
private ProgressBar progressBar;
private MyThread m=new MyThread();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView=(TextView)findViewById(R.id.text);
button=(Button)findViewById(R.id.startButton);
progressBar=(ProgressBar)findViewById(R.id.bar);
progressBar.setMax(100);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
myHandler=new MyHandler();
new Thread(m).start();
System.out.println("onCreate--The Thread is: "+Thread.currentThread().getId());
}
});
}
//在对UI进行更新时,执行时所在的线程为主UI线程
class MyHandler extends Handler{//继承Handler类时,必须重写handleMessage方法
public MyHandler(){
}
public MyHandler(Looper l){
super(l);
}
@Override
public void handleMessage(Message msg) {//执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出
System.out.println("Handler--The ThreadId is: "+Thread.currentThread().getId());
super.handleMessage(msg);
Bundle b=msg.getData();
String textStr0=textView.getText().toString();
String textStr1=b.getString("textStr");
HandlerActivity.this.textView.setText(textStr0+" "+textStr1);//更改TextView中的值
int barValue=b.getInt("barValue");HandlerActivity.this.progressBar.setProgress(barValue);//更改进度条当中的值
}
}
//该线程将会在单独的线程中运行
class MyThread implements Runnable{
int i=1;
@Override
public void run() {
while(i<11){
System.out.println("Thread--The ThreadId is: "+Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg=new Message();
Bundle b=new Bundle();
b.putString("textStr", "线程运行"+i+"次");
b.putInt("barValue", i*10);
i++;
msg.setData(b);
HandlerActivity.this.myHandler.sendMessage(msg);//通过sendMessage向Handler发送更新UI的消息
}
}
}
}
/***
Android Handler 异步消息机制
Handler基本概念:
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分逐个的在消息队列中将消息取出,然后对消息进行出来,就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
Handler 常用方法:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
个人认为Android 中Handler 很像 Web开发中的Ajax。拿jquery 的$.ajax()方法来举例:
$.ajax({
url:"xxxx.jsp",
dataType:"text",
success:function(message){ // 处理返回的结果}
})
首先我们按老规矩先看Demo的效果图:
1、点击 测试 按钮的开启一条线程处理其他比较耗时的业务,相当于 一个Web页面点击页面的某个按钮后调用javascript 的ajax方法去后台去数据,而本身的页面是没变的。
2、是否是异步的呢?从图二可以看出。先打印出了线程中 “start Thread”,才执行 onClick 方法中的 “OnClick........”
3、下面代码效果等于ajax请求的后台的响应,那Java来说就是 printWriter.prinlt(1);
- Thread thread = new Thread()
- {
- public void run()
- {
- Log.i(TAG, "start Thread");
-
- //发送一个空消息到消息队列里面
- //此方法相当于后台往前台Ajax响应结果,在Java当中,相当于一个Action方法里面out.println(1);
- handler.sendEmptyMessage(1);
- };
- };
4、 以下代码相当于ajax的 success:function(message){if(message==1){//do something}}
- if(msg.what ==1)
- {
- txtTest.setText("异步处理结果 === Handler ");
- }
下面看一下具体代码是怎么实现的:
main.xml文件:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:id="@+id/txtTest"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="HandlerTest"
- />
-
-
- <Button android:id="@+id/btnTest"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="测试"
- />
- </LinearLayout>
Activity:
- package com.droidstouc.handler.test;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
- /**
- * Android Handler 异步消息处理机制
- * @author Administrator
- *
- */
- public class HandlerTestActivity extends Activity {
-
-
-
- private static final String TAG="HandlerTestActivity";
-
- private Button btnTest;
- private TextView txtTest;
-
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
-
- txtTest = (TextView) this.findViewById(R.id.txtTest);
- btnTest= (Button) this.findViewById(R.id.btnTest);
-
- //设置 OnClick **
- btnTest.setOnClickListener(new BtnTestOnClickListener());
- }
-
-
-
- //点击测试按钮后调用 BtnTestOnClickListener 的 OnClick 方法
- class BtnTestOnClickListener implements OnClickListener
- {
- @Override
- public void onClick(View v)
- {
- /* //把线程对象放到handler的队列中,线程会马上启动执行
- handler.post(thread);*/
-
- //启动线程
- thread.start();
- try
- {
- // 为了看到异步效果,我让当前线程停止了2秒钟
- Thread.sleep(2000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
-
- Log.i(TAG, "OnClick........");
- }
-
- }
-
-
- // 定义一个Handler,用来异步处理数据
- Handler handler = new Handler()
- {
- //相当于jquery $.ajax方法中的 Success:function(){}
-
- public void handleMessage(android.os.Message msg)
- {
- // 对线程中 handler 返回的结果进行处理
-
- Log.i(TAG, "结果返回,正在处理");
- if(msg.what ==1)
- {
- txtTest.setText("异步处理结果 === Handler ");
- }
-
- };
- };
-
-
-
- Thread thread = new Thread()
- {
- public void run()
- {
- Log.i(TAG, "start Thread");
-
- //发送一个空消息到消息队列里面
- //此方法相当于后台往前台Ajax响应结果,在Java当中,相当于一个Action方法里面out.println(1);
- handler.sendEmptyMessage(1);
- };
- };
- }