一、Handler的定义:
接受子线程发送的数据并配合主线程更新UI。当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理,所以主线程通常又被叫做UI线程。如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,但因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时Handler就可以解决这个问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,把这些消息放入主线程队列中,配合主线程进行更新UI。
Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象。
二、Handler的特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程)。
Handler的两个队列:
1.发送、接受、处理消息–消息队列;
Handler对象维护一个消息队列,有新的消息送来(sendMessage())的时候,把它放在队尾,之后排队到处理该消息的时候,由主线程的Handler对象处理(handleMessage()),整个过程是异步的。
handler.post(Runnable );//将Runnable直接添加入队列
handler.postDelayed(Runnable, long)//延迟一定时间后,将Runnable添加入队列
handler.postAtTime(Runnable,long)//定时将Runnable添加入队列handler.removeCallbacks(thread);//将Runnable从Runnable队列中取出
2.启动、结束、休眠线程–Runnable队列;
Handler对象维护一个线程队列,有新的Runnable送来(post())的时候,把它放在队尾,而处理Runnable的时候,从队头取出Runnable执行。当向队列发送一个Runnable后,立即就返回,并不理会Runnable是否被执行,执行是否成功等。而具体的执行则是当排队排到该Runnable后系统拿来执行的。
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
Handler有两个作用:
l安排消息或Runnable 在某个主线程中某个地方执行post(Runnable)
public class test extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("Current Thread id:"+Thread.currentThread().getId());
handler.post(runnable);
}
//无参构造Handler对象,那么这个Handler将自动与当前运行线程相关联
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
// TODO Auto-generated method stub
System.out.println("Current Thread id:"+Thread.currentThread().getId());
}
};
}
也就是说这个Handler将与当前运行的线程使用同一个消息队列,并且可以处理该队列中的消息。我们直接利用handler对象post了一个runnable对象,相当于直接调用了Runnable对象的run函数,也就说没有经过start函数调用run(),那么就不会创建一个新线程,而是在原有线程内部直接调用run()方法。handler.post()方法并未真正新建线程,只是在原线程上执行而已,我们并未实现异步机制。
l 安排一个动作在不同的线程中执行
public class test extends Activity {
private Handler handler = null;
private HandlerThread thread = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("Current Thread id:"+Thread.currentThread().getId());
//开启一个线程去执行runnable
thread = new HandlerThread("test");
thread.start();
//如果new一个带参构造函数的Handler对象,那么这个Handler对象将与参数所表示的Looper相关联
handler = new Handler(thread.getLooper());
handler.post(runnable);
}
private Runnable runnable = new Runnable() {
public void run() {
// TODO Auto-generated method stub
System.out.println("Current Thread id:"+Thread.currentThread().getId());
}
};
}
Handler是通过HandlerThread 使得子线程与主线程分属不同线程的。实际上,HandlerThread 是一个特殊的线程,它是一个封装好Looper的线程,Looper类用来为线程开启一个消息循环,作用是可以循环的从消息队列读取消息,所以Looper实际上就是消息队列+消息循环的封装。每个线程只能对应一个Looper,除主线程外,Android中的线程默认是没有开启Looper的。
Looper.prepare();启用Looper
Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。