Handler的用途
Handler是子线程(工作线程)与主线程之间的通信桥梁。由于更新UI只能在主线程里完成,所以在子线程里的工作完成后,可以通过Handler来通知主线程更新UI组件。
什么是主线程呢?
当app应用程序启动时创建的第1个线程就是主线程(MainThread)又叫UI线程,因为它专门用于UI的操作。
什么是子线程呢?
子线程,又因其作用而被称为工作线程,是程序员手动创建的,常用于一些耗时的操作,如网络请求、数据加载等。
使用Handler的好处
在实际开发中,常常存在多个线程并发操作UI组件的情况,那么线程安全显得尤为重要。如果想做到既可以多线程并发操作UI,又保证线程安全的话,Handler将会是一个不错的选择。
Handler是异步消息机制模型。
Handler的工作流程
阶段 | 说明 |
---|---|
1.异步通信准备 | (1)在主线程启动时会自动创建Looper消息循环处理器,Looper创建时会同时创建MessageQueue消息队列,创建Looper、MessageQueue完成后,Looper消息循环理器就会自动进入消息循环;(2)在主线程里手动创建Handler处理器对象,此时Handler对象会自动绑定主线程里的Looper、MessageQueue对象。 |
2.消息发送 | 工作线程通过Handler处理器对象发送消息Message到MessageQueue消息队列 |
3.消息循环 | Looper循环器取出MessageQueue中的消息,然后把消息分发给该消息的Handler处理器。 |
4.消息处理 | (1)Handler处理器接收Looper循环器发来的消息;(2)根据消息Message的内容进行UI操作 |
相关的术语的介绍:
- Message:消息对象,用于存储需要操作的通信信息,是Handler对象接收和处理的对象。
- MessageQueue:消息队列,是一个有先进先出特点的数据结构。用于存储Handler对象发送过来的Message消息对象。
- Handler:是工作线程与主线程通信的媒介。它可以向消息队列MessageQueue添加消息Message,也可以接收并处理Looper循环器分发过来的Message消息。
如图所示:
号外!号外!号外!
线程(Thread)、循环器(Looper)、处理者(Handler)之间的关系有如下限制:
- 一个线程Thread只能绑定一个循环器Looper
- 一个循环器Looper可以绑定多个处理器Handler,但是一个处理器Handler只能绑定一个循环器Looper。
Handler的一般使用方法
有sendMessage、post两种方式。
(1)使用 Handler.sendMessage()
此种方式分为Handler子类(内部类)、匿名 Handler子类两种。
Handler子类(内部类):
package com.ti.controlsound;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
/**
* 方式1:Handler子类(内部类)
* 1、自定义Handler子类(继承Handler类)
* 2、重写handleMessage()方法
*/
// 第一步:新建Handler子类(内部类)
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// TODO 需执行的UI操作
Log.d("MESSAGE",(String) msg.obj);
}
}
// 第二步:在主线程中创建Handler实例
private Handler mHandler = new MyHandler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// 第三步:创建所需的消息对象
Message msg = Message.obtain(); // 实例化消息对象
msg.what = 1; // 消息标识
msg.obj = "Hello World"; // 消息内容存放
// 第四步:在工作线程中,通过Handler发送消息到消息队列中
mHandler.sendMessage(msg);
}
}).start();// 第五步:开启工作线程(同时启动了Handler)
}
}
匿名 Handler子类:
package com.ti.controlsound;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
/**
* 方式2:匿名内部类
*/
// 第一步:在主线程中通过匿名内部类创建Handler类对象
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO 需执行的UI操作
Log.d("MESSAGE",(String) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// 第二步:创建所需的消息对象
Message msg = Message.obtain(); // 实例化消息对象
msg.what = 1; // 消息标识
msg.obj = "Hello World"; // 消息内容存放
// 第三步:在工作线程中,通过Handler发送消息到消息队列中
mHandler.sendMessage(msg);
}
}).start();// 第四步:开启工作线程(同时启动了Handler)
}
}
(2)使用Handler.post()
package com.ti.controlsound;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
// 第一步:在主线程中创建Handler类对象
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO 需执行的UI操作
Log.d("MESSAGE", (String) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// 第二步:在工作线程中 发送消息到消息队列中和指定操作UI内容
// 需传入1个Runnable对象
mHandler.post(new Runnable() {
@Override
public void run() {
// 需执行的UI操作
}
});
}
}).start();// 第三步:开启工作线程(同时启动了Handler)
}
}
Handler就介绍到这里。
特大号外!!!
上面使用Handler的方式都有可能引发内存溢出,相关解决方法,请查看《Android性能优化之Handler内存溢出》。谢谢