1 工作原理
内部原理 = Thread类 + Handler类机制,即:
- 通过继承Thread类,快速地创建1个带有Looper对象的新工作线程
- 通过封装Handler类,快速创建Handler & 与其他线程进行通信
2 使用步骤
HandlerThread的使用步骤有5个:
// 步骤1:创建HandlerThread实例对象
// 传入参数 = 线程名字,作用 = 标记该线程
HandlerThread mHandlerThread = new HandlerThread("handlerThread");
// 步骤2:启动线程
mHandlerThread.start();
// 步骤3:创建工作线程Handler & 复写handleMessage()
// 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
// 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
Handler workHandler = new Handler( handlerThread.getLooper() ) {
@Override
public boolean handleMessage(Message msg) {
...//消息处理
return true;
}
});
// 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
// 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
// a. 定义要发送的消息
Message msg = Message.obtain();
msg.what = 2; //消息的标识
msg.obj = "B"; // 消息的存放
// b. 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
// 步骤5:结束线程,即停止线程的消息循环
mHandlerThread.quit();
3 源码分析
3.1 创建HandlerThread的实例对象
/**
* 源码分析:HandlerThread类的构造方法
*/
public class HandlerThread extends Thread {
// 继承自Thread类
int mPriority; // 线程优先级
int mTid = -1; // 当前线程id
Looper mLooper; // 当前线程持有的Looper对象
// HandlerThread类有2个构造方法
// 区别在于:设置当前线程的优先级参数,即可自定义设置 or 使用默认优先级
// 方式1. 默认优先级
public HandlerThread(String name) {
// 通过调用父类默认的方法创建线程
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
// 方法2. 自定义设置优先级
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
...
}
总结
-
HandlerThread
类继承自Thread
类 - 创建
HandlerThread
类对象 = 创建Thread
类对象 + 设置线程优先级 = 新开1个工作线程 + 设置线程优先级
3.2 启动线程
/**
* 源码分析:此处调用的是父类(Thread类)的start(),最终回调HandlerThread的run()
*/
@Override
public void run() {
// 1. 获得当前线程的id
mTid = Process.myTid();
// 2. 创建1个Looper对象 & MessageQueue对象
Looper.prepare();
// 3. 通过持有锁机制来获得当前线程的Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
// 发出通知:当前线程已经创建mLooper对象成功
// 此处主要是通知getLooper()中的wait()
notifyAll();
// 此处使用持有锁机制 + notifyAll() 是为了保证后面获得Looper对象前就已创建好Looper对象
}
// 4. 设置当前线程的优先级
Process.setThreadPriority(mPriority);
// 5. 在线程循环前做一些准备工作 ->>分析1
// 该方法实现体是空的,子类可实现 / 不实现该方法
onLooperPrepared();
// 6. 进行消息循环,即不断从MessageQueue中取消息 & 派发消息
Looper.loop();
mTid = -1;
}
}
/**
* 分析1:onLooperPrepared();
* 说明:该方法实现体是空的,子类可实现 / 不实现该方法
*/
protected void onLooperPrepared() {
}
总结
- 为当前工作线程(即步骤1创建的线程)创建1个Looper对象 & MessageQueue对象
- 通过持有锁机制来获得当前线程的Looper对象
- 发出通知:当前线程已经创建mLooper对象成功
- 工作线程进行消息循环,即不断从MessageQueue中取消息 & 派发消息
3.3 创建工作线程Handler & 复写handleMessage()
/**
* 具体使用
* 作用:将Handler关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
* 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
*/
Handler workHandler = new Handler( handlerThread.getLooper() ) {
@Override
public boolean handleMessage(Message msg) {
...//消息处理
return true;
}
});
/**
* 源码分析:handlerThread.getLooper()
* 作用:获得当前HandlerThread线程中的Looper对象
*/
public Looper getLooper() {
// 若线程不是存活的,则直接返回null
if (!isAlive()) {
return null;
}
// 若当前线程存活,再判断线程的成员变量mLooper是否为null
// 直到线程创建完Looper对象后才能获得Looper对象,若Looper对象未创建成功,则阻塞
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
// 此处会调用wait方法去等待
wait();
} catch (InterruptedException e) {
}
}
}
// 上述步骤run()使用 持有锁机制 + notifyAll() 获得Looper对象后
// 则通知当前线程的wait()结束等待 & 跳出循环
// 最终getLooper()返回的是在run()中创建的mLooper对象
return mLooper;
}
- 在获得
HandlerThread
工作线程的Looper
对象时存在一个同步的问题:只有当线程创建成功 & 其对应的Looper
对象也创建成功后才能获得Looper
的值,才能将创建的Handler 与 工作线程的Looper对象绑定,从而将Handler绑定工作线程 - 解决方案:即保证同步的解决方案 = 同步锁、
wait()
和notifyAll()
,即 在run()
中成功创建Looper
对象后,立即调用notifyAll()
通知getLooper()
中的wait()
结束等待 & 返回run()
中成功创建的Looper
对象,使得Handler
与该Looper
对象绑定
3.4 使用工作线程Handler向工作线程的消息队列发送消息
/**
* 具体使用
* 作用:在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
* 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
*/
// a. 定义要发送的消息
Message msg = Message.obtain();
msg.what = 2; //消息的标识
msg.obj = "B"; // 消息的存放
// b. 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
3.5 结束线程,即停止线程的消息循环
/**
* 具体使用
*/
mHandlerThread.quit();
/**
* 源码分析:mHandlerThread.quit()
* 说明:
* a. 该方法属于HandlerThread类
* b. HandlerThread有2种让当前线程退出消息循环的方法:quit() 、quitSafely()
*/
// 方式1:quit()
// 特点:效率高,但线程不安全
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
// 方式2:quitSafely()
// 特点:效率低,但线程安全
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
上述2个方法最终都会调用MessageQueue.quit(boolean safe)
移步Android Handler机制7--消息移除、关闭及其他
网友评论