先介绍一下与Handler一起工作的几个组件。
为了保证Handler关联的线程有Looper对象,可分一下两种情况:
调用Looper的静态loop()方法可以启动Looper对象。loop()方法使用一个死循环不断的取出MessageQueue中的消息,并将取出的消息发给给消息对应的Handler进行处理。
归纳,Looper、MessageQueue、Handler各自的作用如下:
在自己创建的线程中使用Handler的步骤:
实例:
public class MainActivity extends Activity {
private TextView textView;
private Button showButton;
CallThread callThread;
Handler handler;
class CallThread extends Thread
{
@Override
public void run()
{
Looper.prepare();
handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1)
{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this,textView.getText(),LENGTH_LONG).show();
}
}
};
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
showButton = (Button) findViewById(R.id.showBtn);
callThread = new CallThread();
callThread.start();
showButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//callThread在此处初始化不行,必须放到上面初始化,
// 否则导致程序无法运行,本人刚学Android,等以后知道了才解释吧。
// callThread = new CallThread();
// callThread.start();
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
});
}
}
效果:
点击SHOW TOAST按钮,5s后按钮下面显示Toast的内容为Hello World.
如果将上述代码该为:
showButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this,textView.getText(),LENGTH_LONG).show();
}
}).start();
}
});
点击SHOW TOAST按钮,5s后不会出现Toast,程序运行失败,怎么回事?
报的错误为:
java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
当然,有人会问UI线程向非UI线程之间进行通信时,每次都得写Looper对象,那岂不是很麻烦。故Android已经帮我们实现好了自带Looper的线程,那就是HandlerThread类。
Android对HandlerThread的描述:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
使用HandlerThread的步骤:
handlerThread = new HandlerThread("handlerThread");
//创建handlerThread后一定要记得start.
handlerThread.start();
Looper looper = handlerThread.getLooper();
3 创建Handler,通过Looper初始化
handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。如果想让HandlerThread退出,则需要调用handlerThread.quit();
注:如果hander传递的是Message,则需要重写handlerMessage()函数。
handler = new Handler(looper)
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1)
{
//要处理的事情
}
}
};
或者自己创建个线程类继承HandlerThread类并实现CallBack接口以重写CallBack里面的handlerMessage方法,在handlerMessage方法中来处理自己的逻辑。
如果hander传递的是Runnable对象,则不需要重写handlerMessage()函数。
使用HandlerThread重写上面的Demo:
public class MainActivity extends Activity {
private TextView textView;
private Button showBtn;
private HandlerThread handlerThread;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread("handlerThread");
//创建handlerThread后一定要记得start.
handlerThread.start();
Looper looper = handlerThread.getLooper();
//handler与谁关联不是看在哪创建handler,而是看handler创建时与哪个线程的looper挂钩。
handler = new Handler(looper)
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1)
{
Toast.makeText(getApplicationContext(),textView.getText()
,Toast.LENGTH_LONG).show();
}
}
};
textView = (TextView) findViewById(R.id.textView);
showBtn = (Button) findViewById(R.id.showBtn);
showBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handler.sendEmptyMessageDelayed(1,5000);
}
});
}
}
为什么要使用HandlerThread。
1.开发中如果多次使用类似new Thread(){…}.start()。这种方式开启一个子线程,会创建多个匿名线程,使得程序运行起来越来越慢,
而HandlerThread自带Looper使他可以通过消息来多次重复使用当前线程,节省开支;
2.android系统提供的Handler类内部的Looper默认绑定的是UI线程的消息队列,对于非UI线程又想使用消息机制,那么HandlerThread内部的Looper是最合适的,它不会干扰或阻塞UI线程。