- 《Android Handler机制》
- 《Android Handler分析(一) Handler和Message详解》
- 《Android Handler分析 (二) MessageQueue详解》
- 《Android Handler分析 (三) Looper详解和Handler其他知识》
- 《Android 中的 HandlerThread 类详解》
简介
HandlerThread
类继承至 Thread
类,你可以把它看做是一个普通的线程类;当然,既然我们今天要说它,就不能在把它看做是一个普通的线程类了类处理了。HandlerThread
类与普通的线程类的主要区别就是:重写 run()
方法,并且创建了一个属于自己线程包含消息队列 Looper
对象;同时提供了 getLooper()
方法给外界获取 Looper
对象。
好处
- 开发中如果多次使用类似
new Thread(){...}.start()
这种方式开启一个子线程,会创建多个匿名线程,难于管理且使得程序运行起来越来越慢,而HandlerThread
自带Looper
包含一个独立的队列使它可以通过消息来多次重复使用当前线程,节省开支; - 既然
HandlerThread
自带包含队列的Looper
,那么它就可以分担主线程的Looper
队列的压力; - Android系统提供的
Handler
类内部的Looper
默认绑定的是UI线程的消息队列,对于非UI线程又想使用消息机制,那么HandlerThread
内部的Looper
是最合适的,它不会干扰或阻塞UI线程。
使用方式
private HandlerThread handlerThread; // HandlerThread 对象
private Handler workHandler; // 工作线程的Handler对象
private Handler uiHandler = new Handler() { // 主线程/UI线程 的Handler对象
@Override
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "接收到刷新界面的消息: " + msg.what, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread("handler_thread_test");
handlerThread.start();
// handlerThread.quit(); // 退出
// 创建工作线程的Handler对象
workHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 模拟耗时操作
SystemClock.sleep(msg.arg1);
Log.i("MainActivity", "Thread: " + Thread.currentThread().getName());
// 发送刷新界面消息
uiHandler.sendEmptyMessage(msg.what);
}
};
Message message;
for (int i = 1; i <= 3; i++) {
message = Message.obtain();
message.what = i;
message.arg1 = 1000 * i;
// 将 Message 对象发送到工作线程
workHandler.sendMessage(message);
}
}
源码解析
1.构造方法
// 指定线程名称
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT; // 优先级 0
}
// 指定线程名称和优先级 优先级:-19 ~ 19 ,19 表示优先级最低;默认 0
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
2.初始化方法,按需重写
protected void onLooperPrepared() {
}
默认空实现,用于开启轮询前进行初始化。
3.getLooper()
方法
public Looper getLooper() {
// 判断线程状态
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
// 如果线程已经启动,等待 Looper 创建完成
synchronized (this) {
while (isAlive() && mLooper == null) {
// 如果线程是正在运行状态但是 mLooper 对象为 null,线程等待
// 提前说明一下,是在 run() 方法中唤醒的
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
4.run()
方法
@Override
public void run() {
mTid = Process.myTid();
// 调用 Looper.prepare() 方法,将线程变为 Looper 线程
Looper.prepare();
synchronized (this) {
// 获取当前线程的 Looper 对象
mLooper = Looper.myLooper();
// 唤醒线程,wait() 等待方法在 getLooper() 方法中调用
notifyAll();
}
// 设置线程优先级
Process.setThreadPriority(mPriority);
// 回调初始化方法
onLooperPrepared();
// 启动轮询器,开始对消息队列进行轮询
Looper.loop();
mTid = -1;
}
5.结束方法
// 调用 looper.quit() 退出,清除全部消息(包括延时消息和非延时消息)
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
// 调用 looper.quitSafely() 退出,清除所有的延时消息,把所有非延时消息进行发送
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
6.其他方法
// 获取当前线程的 Handler 对象
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
// 获取当前线程 id
public int getThreadId() {
return mTid;
}
HandlerThread
类源码非常简单,就是在普通的线程中创建了一个Looper
对象使之变为了一个Looper
线程。类的源码说明在注释上面已经非常清晰,就不在重复了。
总结
HandlerThread
将Looper
转到子线程中处理,分担了MainLooper
的工作量,降低了主线程的压力,使主界面更流畅;- 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。
HandlerThread
本质是一个线程,在线程内部,代码是串行处理的;- 由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理;
HandlerThread
拥有自己的消息队列,它不会干扰或阻塞UI线程;- 对于网络操作,
HandlerThread
并不适合,因为它只有一个线程,延时可能比较严重。
网友评论