再介绍另外一个在开发中用的很多的异步大杀器,用于处理异步消息的,处理一些耗时操作,处理后台运行的程序并且要更新ui的情况,他就是Handler。 Handler主要接受子线程发送的数据, 并用此数据配合主线程更新UI.。
当应用程序操作应用程序的时候,出现一些比较耗时的操作,譬如 从网上下载数据,读取本地较大的文件,这时不能把这些操作 放在主线程,因为这样会阻塞主线程,而且如果5秒钟还没有完成的话,就会出席那ANR(应用程序无响应)的错误。所以我们需要把耗时操作放在子线程进行操作。这样是可以处理了主线程被阻塞的麻烦,但是如果如果我们想更新UI,而在子线程中操作是不安全的,无法预料后面发生的事情(Andoid UI toolkit不是线程安全的,所以注意在android使用线程的两个点:a > 不要阻塞UI线程; b > 不要再主线程外的线程操控UI线程(即更新UI)),这个时候就体现出了Handler的价值了。
Handler是在主线程(UI线程)中运行,他与子线程通过Message来传递数据(通过SendMessage()发送个主线程),而主线程中有个消息队列MessageQueue来存储,HandleMessage()一个一个的从队列中取出消息,并相应的进行处理,更新ui。
当创建了Handler对象,他就会与他所在的线程以及消息队列进行绑定,这样发送Message或Runable,就可以发送给消息队列做相应的处理了。一个线程可以有多个handler,各自处理各自的相对应的消息;但是一个线程只有一个looper,当然也就只有一个消息循环。这里还要注意一个问题,在一个普通的子线程中创建handler,因为没有调用Looper.prepare(),没有Looper实例,所以会出现异常,同时这也说明一个普通的子线程没有Looper实例,没有消息循环。所以在一个普通的子线程中发送消息是不行的,当然我们可以自己创建Looper实例(a.子线程中创建一个消息队列(就是Looper对象,通过prepare(),loop()); b.得到主线程中得消息队列,操控主线程的消息队列Looper.getMainLooper())。但是我们一般这么做,而是使用另外一个类,叫做HandlerThread,这个自身有Looper实例。
看下下面的代码片段:
public class HandlerDemo extends Activity {
private final static int MESSAGE_ID = 5;
private TestHandler1 mTestHandler1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTestHandler1 = new TestHandler1(); // 创建handler实例
Button btn = (Button) findViewById(R.id.clcik);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread(new Runnable(){ // 从子线程发送消息给ui线程
@Override
public void run() {
// TODO Auto-generated method stub
// 发送消息
// 直接从handler获取message对象,当然也可以new一个,但是推荐前一个
Message msg = mTestHandler1.obtainMessage();
Bundle b = new Bundle();
b.putString("color", "red");
// 给handler发送的数据,放入message中
msg.setData(b);
msg.what = MESSAGE_ID;
mTestHandler1.sendMessage(msg);
}
}).start();
}
});
}
private class TestHandler1 extends Handler // 实现handler
{
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (msg.what == MESSAGE_ID) {
Bundle b = msg.getData();
String colorStr = b.getString("color");
Log.d("HandlerDemo", "TestHandler1---------"+colorStr);
}
}
}
}
继承于handler的子类TestHandler1,并在主线程中分别创建对象;
创建一个子线程,在子线程用主线程中定义的mTestHandler1对象,发送消息给主线程,并在主线程中的HandleMessage中做相应的处理;
Message msg = mTestHandler1.obtainMessage();
Bundle b = new Bundle();
b.putString("color", "red");
// 给handler发送的数据,放入message中
msg.setData(b);
msg.what = MESSAGE_ID;
mTestHandler1.sendMessage(msg);
这一部分会在Message中做相应的介绍,这里就不解释了。
总结:
1.handler的作用(为什么使用handler):
1)按计划发送消息或执行某个Runnanble(使用POST方法),类似定时器;
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程);
2.当handler在一个线程中创建,就会与他所在的线程和消息队列进行绑定;
3.一个线程对应一个Looper(消息循环),一个MessageQueue(消息队列)
4.一个线程中可以对应多个handler,但是共用一个Looper和MessageQueue;
5.handler可以从任何线程发送消息(前提必须有looper实例);