一、为什么要用Handler
当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响应用户并分发事件等。所以一般在主线程中不要执行比较耗时的操作,如联网下载数据等,否则出现ANR(应用无响应)错误。所以就将这些操作放在子线程中,但是由于Android子线程是不安全的,所以只能在主线程中更新UI。Handler就是用来 子线程和创建Handler的线程进行通信的。
二、理解Handler机制的使用
开始今天的学习之前,我们先来了解一些概念:
Android是消息驱动的,实现消息驱动有几个要素:
消息的表示:Message
消息队列:MessageQueue
消息循环:用于循环取出消息进行处理:Looper
消息处理:消息循环从消息队列中取出消息后要对消息进行处理:Handler
handler类有两种主要用途:
1、按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。
2、把一个对另外线程对象的操作请求放入消息队列中,从而避免线程间冲突。
三、Handler机制的使用
Handler工具类在多线程中有两方面的应用:
1、发送消息,在不同的线程间发送消息,使用的方法为sendXXX();
android.os.Handler对象通过下面的方法发送消息的:
sendEmptyMessage(int),发送一个空的消息;
sendMessage(Message),发送消息,消息中可以携带参数;
sendMessageAtTime(Message, long),未来某一时间点发送消息;
sendMessageDelayed(Message, long),延时Nms发送消息。
2、计划任务,在未来执行某任务,使用的方法为postXXX();
android.os.Handler对象通过下面的方法执行计划任务:
post(Runnable),提交计划任务马上执行;
postAtTime(Runnable, long),提交计划任务在未来的时间点执行;
postDelayed(Runnable, long),提交计划任务延时Nms执行。
下面我们用代码来实现:
1、使用Message消息
public class HandlerActivity extends AppCompatActivity implements View.OnClickListener {
TextView textHandler;
Button buttonMessage, buttonRunnable;
Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
textHandler = (TextView) findViewById(R.id.text_handler);
buttonMessage = (Button) findViewById(R.id.button_message);
buttonRunnable = (Button) findViewById(R.id.button_runnable);
buttonMessage.setOnClickListener(this);
buttonRunnable.setOnClickListener(this);
handler = new MyHandler();
}
public class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.e("测试", String.valueOf(msg.arg1 + msg.arg2));
textHandler.setText(msg.obj.toString());
break;
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_message:
//使用Message的方式传递消息
new Thread(new Runnable() {
@Override
public void run() {
Message message = handler.obtainMessage();
message.arg1 = 1;
message.arg2 = 2;
message.obj = "小米";
message.what = 1;
message.sendToTarget();
// 也可以使用这种方式发送message
// handler.sendMessage(message);
}
}).start();
break;
case R.id.button_runnable:
//使用Runnable的方式传递消息
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
//这句话其实是在创建handler的线程中执行的,这是则是在主线程中运行的
//说明只是把runnable里的run方法放到UI线程里运行,并不会创建新线程
//因此我们可以在子线程中将runnable加入到主线程的MessageQueue,然后主线程将调用runnable的方法,可以在此方法中更新主线程UI。
textHandler.setText("小米2");
}
});
}
}).start();
break;
}
}
}
2、使用Runnable传递
写在上面代码中!
四、在线程中创建Handler传递消息,还有HandlerThread的使用
如何在线程当中实例化Handler。在线程中实例化Handler我们需要保证线程当中包含Looper(注意:UI-Thread默认包含Looper)。
为线程创建Looper的方法如下:在线程run()方法当中先调用Looper.prepare()初始化Looper,然后再run()方法最后调用Looper.loop(),这样我们就在该线程当中创建好Looper。(注意:Looper.loop()方法默认是死循环)。
我们实现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.
Handler机制的分发中心就在Looper中的loop(),HandlerThread将loop转到子线程中处理,降低了主线程的压力,使主界面更流畅,其实 说白了,创建HandlerThread,只是为了用此线程的looper 最终的runnable都还是post到主线程运行(已用Toast测试过)
使用步骤
尽管HandlerThread的文档比较简单,但是它的使用并没有想象的那么easy。
1、创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread(“HandlerThread”);
handlerThread.start(); //创建HandlerThread后一定要记得start()
2、获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
3、创建Handler,通过Looper初始化
Handler handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();
public class HandlerActivity extends AppCompatActivity implements View.OnClickListener {
Button threadHandler, handlerThread;
Handler threadHanlder;
Handler hanlderThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
threadHandler = (Button) findViewById(R.id.button_thread_handler);
handlerThread = (Button) findViewById(R.id.button_handlerthread);
threadHandler.setOnClickListener(this);
handlerThread.setOnClickListener(this);
//使用子线程中创建Handler
ThreadHandler threadHandler = new ThreadHandler();
threadHandler.start();
//创建HandlerThread
HandlerThread handlerThread = new HandlerThread("hanlderThread");
handlerThread.start();
hanlderThread = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 2:
Log.e("HandlerThread", Thread.currentThread().toString());
break;
}
}
};
Log.e("MianThread", Thread.currentThread().toString());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_thread_handler:
threadHanlder.sendEmptyMessage(1);
break;
case R.id.button_handlerthread:
hanlderThread.sendEmptyMessage(2);
break;
}
}
//使用子线程实现Hanlder
public class ThreadHandler extends Thread {
@Override
public void run() {
super.run();
Looper.prepare();
threadHanlder = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.e("ThreadHandler", Thread.currentThread().toString());
break;
}
}
};
Looper.loop();
}
}
}
布局: