androidsdk:
一个Handler允许你发送和处理消息(Message)以及与一个线程的消息队列相关的Runnable对象。每个Handler实例都和单个线程以及该线程的消息队列有关。当你创建了一个新Handler,它就会和创建它的线程/消息队列绑定,在那以后,它就会传递消息以及runnable对象给消息队列,然后执行它们。
需要使用Handler有两大主要的原因:
(1)在将来的某个时间点调度处理消息和runnable对象;
(2)将需要执行的操作放到其他线程之中,而不是自己的;
调度处理消息是通过调用
post(Runnable),
postAtTime(Runnable, long)
postDelayed(Runnable, long),
sendEmptyMessage(int),
sendMessage(Message),
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(需要复写Handler的handleMessage方法)
在Android中,规定只能由UI 线程来刷新UI(因为子线程太多,子线程可以刷新UI的话,很容易冲突报错)。Handler在开发中主要用来接收子线程的数据。主线程据此来刷新页面。耗时的操作一般不放在主线程中(否则Android会弹出一个ANR无响应对话框,然后提示按“Force quit”或是“Wait”),而是新建一个Thread子线程,在子线程中完成耗时的操作。即:UI 线程发送命令到子线程,子线程完成命令,并将数据返回给UI线程。
而若在主线程中实例化一个Handler对象,例如:
Handler mHandler = new Handler();
此时并没有新派生一个线程来执行此Handler,而是将此Handler附加在主线程上,因此如果在handler里执行的还是耗时操作,那么Android还是会弹出ANR对话框。
Handler handler = new Handler(){
public void run() { @Override
public void handleMessage(Message msg) {
//Subclasses must implement this to receive messages.
super.handleMessage(msg);
}
};
使用方法:
-
默认的Handler(消息处理队列挂在主线程上)
在onCreate()方法后new handler并写入handler需要执行的语句,在之后的按钮监视器中调用执行。 -
消息队列仍绑定在主线程上,但在子线程中发送消息。
new handler并写入handler需要执行的语句,之后新建一个
Thread workThread = new Thread() {
public void run() {
}
}
在该线程中调用handler。这时可以在run方法内做任何耗时的操作,然后将结果以消息形式投递到主线程的消息队列中
- 将消息队列绑定到子线程上,主线程只管通过Handler往子线程的消息队列中投递消息即可。
在onCreate方法中声明Looper,并调用mHandler相关方法。
Looper looper = myLooperThread.getLooper();
mHandler = new MyHandler(looper);
之后写MyHandler类,并重写handleMessage类, 现在在可以执行任何耗时的操作
class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
}
- 自己创建新的线程,然后在新线程中创建Looper,主线程调用子线程中的发消息方法,将消息发给子线程的消息队列。
实现过程
handler基本使用:new Handler对象,在handleMessage中提供收到消息后相应的处理方法。
当调用sendEmptyMessage发送一个msg,Message对象被放入一个MessageQueue队列,该队列属于某个Looper对象,每个Looper对象通过ThreadLocal.set(new Looper())同一个Thread绑定。Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法。
因此建议在主线程中新建handler。
如果在自己的线程中新建handler,有时会报错:主线程已经建立一个Looper了,并调用 了Looper.prepareMainLooper(); Looper.loop()。在prepareMainLooper方法中新建了一个looper对象,并与当前进程进行了绑定,而在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用msg.target.dispatchMessage(msg)。进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理。
在新建Handler时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
若Looper对象没有创建,就会抛异常*Can't create handler inside thread that has not called *
所以我们在一个新线程中要创建一个Handler就需要这样写:
class MyThread extends Thread {
public void run() {
Log.d(Constant.TAG,
MessageFormat.format("Thread[{0}]-- run...",
Thread .currentThread().getName())); // 其它线程中新建一个handler
Looper.prepare();
myThreadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
Log.d(Constant.TAG,
MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...",
Thread .currentThread().getName()));
}
};
Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
}
}
Looper.prepare():创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper
参考资料:
http://blog.csdn.net/yuzhiboyi/article/details/7562262
http://blog.csdn.net/stonecao/article/details/6417364
网友评论