什么是Handlder?
源码对Handler的注释为—Handler是用来结合线程的消息队列来发送、处理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会关联一个线程和该线程的消息队列。当你创建一个Handler的时候,从这时开始,它就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnalbe分发到消息队列,并在它们出队的时候处理掉。
在了解Handler之前,先来了解几个基础概念。
- UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue
- Message:Handler接收与处理的消息对象
- MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue
- Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理
- Handler:作用就是发送与处理信息
简单的来说,当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理。由于 Handler 创建在主线程,处理消息的方法也运行在主线程,因此上述中消息被 Looper 交回给 Handler 的时候就实现了“线程切换”。
Handlder作用
- 执行定时任务:指定任务时间,在某个具体时间或某个时间段后执行特定的任务操作,例如使用Handler提供的postDelayed(Runnable r,long delayMillis)方法指定在多久后执行某项操作。
- 线程间的通信:在执行较为耗时的操作时,Handler负责将子线程中执行的操作的结果传递到UI线程,然后UI线程再根据传递过来的结果进行相关UI元素的更新。
对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中(这句话稍后会进行详细解释),在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
public class TestActivity extends AppCompatActivity implements View.OnClickListener {
Button btn1, btn2;
TextView tv1;
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
tv1 = findViewById(R.id.tv1);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
tv1.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");
}
});
}
}).start();
break;
case R.id.btn2:
new Thread(new Runnable() {
@Override
public void run() {
// 延迟3S执行
handler.postDelayed(new Runnable() {
@Override
public void run() {
tv1.setText("使用Handler.postDelayed在工作线程中发送一段执行到消息队列中,在主线程中延迟3S执行。");
}
}, 3000);
}
}).start();
break;
}
}
}
有一点值得注意的是:对于Post方式而言,它其中Runnable对象的run()方法的代码,均运行在主线程上(虽然看上去是写在子线程当中的),如果我们在这段代码里打印日志输出线程的名字,会发现输出的是Main Thread的名字。所以对于这段代码而言,不能执行在UI线程上的操作。
Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。
public class TestActivity extends AppCompatActivity implements View.OnClickListener {
Button btn1, btn2;
TextView tv1;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
System.out.println("handleMessage thread id " + Thread.currentThread().getId());
System.out.println("msg.arg1:" + msg.arg1);
System.out.println("msg.arg2:" + msg.arg2);
break;
case 99:
System.out.println("handleMessage thread id " + Thread.currentThread().getId());
System.out.println("msg.arg1:" + msg.arg1);
System.out.println("msg.arg2:" + msg.arg2);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
tv1 = findViewById(R.id.tv1);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
new Thread() {
@Override
public void run() {
//处理信息
try {
//模拟费时操作
System.out.println("run thread id " + Thread.currentThread().getId());
sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
Message msg = new Message();
// 也可以用下面两种方法获得Message
// Message msg1=Message.obtain();
// Message msg2=handler.obtainMessage();
msg.what = 0;//msg.what的类型是int型,作为msg的识别码
msg.arg1 = 1;//msg.arg1的类型是int型,可以传递简单的参数
msg.arg2 = 2;//msg.arg2的类型是int型,可以传递简单的参数
msg.obj = "Object类型";//msg.obj是Object型,可以传递任意参数
//将Message发送给handler
handler.sendMessage(msg);
}
}.start();
break;
case R.id.btn2:
new Thread() {
@Override
public void run() {
//处理信息
try {
//模拟费时操作
System.out.println("run thread id " + Thread.currentThread().getId());
sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Message msg = new Message();
// 也可以用下面两种方法获得Message
// Message msg1=Message.obtain();
// Message msg2=handler.obtainMessage();
msg.what = 99;//msg.what的类型是int型,作为msg的识别码
msg.arg1 = 100;//msg.arg1的类型是int型,可以传递简单的参数
msg.arg2 = 101;//msg.arg2的类型是int型,可以传递简单的参数
msg.obj = "Object类型";//msg.obj是Object型,可以传递任意参数
//将Message发送给handler
handler.sendMessage(msg);
}
}.start();
break;
}
}
}
log输出如下
2019-01-19 22:31:11.653 5221-5249/com.testingapp I/System.out: run thread id 245
2019-01-19 22:31:12.665 5221-5221/com.testingapp I/System.out: handleMessage thread id 2
2019-01-19 22:31:12.666 5221-5221/com.testingapp I/System.out: msg.arg1:1
2019-01-19 22:31:12.666 5221-5221/com.testingapp I/System.out: msg.arg2:2
2019-01-19 22:31:37.770 5221-5250/com.testingapp I/System.out: run thread id 246
2019-01-19 22:31:39.780 5221-5221/com.testingapp I/System.out: handleMessage thread id 2
2019-01-19 22:31:39.780 5221-5221/com.testingapp I/System.out: msg.arg1:100
2019-01-19 22:31:39.781 5221-5221/com.testingapp I/System.out: msg.arg2:101