소개
HandlerThread는
Thread를
상속 하고
Looper를 내부적으로 캡슐화합니다 . handlerThread.start() 메서드를 호출한 후 Looper 와 MessageQueue가 내부적으로 생성되며 이 Looper 객체를 통해 Handler를 인스턴스화 한 다음 이 Handler를 다른 스레드에서 사용할 수 있습니다 .
1. 기존의 Thread + Handler 방식을 사용하여 스레드 간 통신 실현
Looper 객체를 직접 구현한 다음 Looper 루프에 Handler 객체를 생성하여 Handler 메시지를 수신하고 해당 작업을 수행해야 합니다.
public Handler threadHandler;
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
threadHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理消息,因为这个方法是在子线程调用,所以要在这执行耗时任务
}
};
Looper.loop();
}
}).start();
2. HandlerThread를 사용하여 스레드 간 통신 실현
먼저 HandlerThread 인스턴스를
생성한
다음
handlerThread.start()를 호출하여
Looper 객체를
생성한
다음 handlerThread.getLooper() 를 통해 HandlerThread 에서 Looper 객체를 가져오고 이 Looper 객체 를 기반으로 핸들러를 생성하여 하위 스레드를 처리합니다. 논리.
HandlerThread handlerThread = new HandlerThread("handler-thread");
handlerThread.start(); // 必须在Handler创建前调用,因为线程start后才会创建Looper
Handler threadHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理消息,在子线程调用,所以要在这执行耗时任务
}
};
실현원리
public class HandlerThread extends Thread {
int mPriority; // 线程优先级
int mTid = -1; // 线程Id
Looper mLooper; // Looper循环器对象
private @Nullable Handler mHandler; // Handler 对象
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* 开启Looper循环之前的准备工作
* 复写之后,添加自己的逻辑
*/
protected void onLooperPrepared() { }
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* 此方法返回与此线程关联的循环器。如果这个线程没有启动或者
* 因为任何原因isAlive()返回false,这个方法将返回null。
* 如果这个线程已经启动,这个方法将阻塞,直到循环器初始化为止。
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 如果线程已经启动,则会等待,直到创建了循环器。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* 返回一个已经与此线程进行关联的 Handler对象。
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* 这是退出循环器Looper的方法,一旦调用了quit()方法,消息队列中的消息将会立即停止处理,
* 并且之后发来的所有消息都会失败。比如sendMessage()方法会返回false。
* 这是不安全的一种退出方式。即不管是否正在处理消息,直接移除所有回调。
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* 安全的退出Looper循环,
* 会等待正在处理的消息处理完后再退出。
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* 获取线程Id
*/
public int getThreadId() {
return mTid;
}
}
HandlerThread의 우선 순위 우선 순위
HandlerThread 스레드
의 우선 순위를 합리적으로 할당 하고 스레드를 어느 정도 최적화하십시오.
기본 우선순위는
process.THREAD_PRIORITY_DEFAULT
이며 값은
"0" 입니다
.
우선 순위의 값 범위는 "-20 ~ 19"이며 값이 작을수록 우선 순위가 높습니다. 우선 순위가 높은 스레드는 더 많은 CPU 리소스를 얻게 되며 그 반대의 경우도 마찬가지입니다.
그러나 HandlerThread
는 작업자 스레드와 같이
높은 우선 순위를 설정할 필요가 없으므로 필요에 따라 합리적인 우선 순위 수준을 설정해야 합니다.
HandlerThread 사용 시나리오
Looper 를
캡슐화하기 때문에 Thread + Looper 장면
에 속합니다
. 하위 스레드에서 시간이 많이 걸리는 작업 및 다중 작업 작업을 실행합니다.
로컬 IO 작업의 경우 :
HandlerThread는 로컬 IO 읽기 및 쓰기 작업을 처리하는 데 사용할 수 있습니다. 대부분의 로컬 IO 작업은 밀리초가 걸리므로 단일 스레드 + 대기열의 형태인 HandlerThread의 경우 차단이 발생하지 않습니다. 또한 postAtFrontQueue() 메서드를 사용하여 로컬 IO를 읽을 수 있습니다. 그러면 실행을 위해 읽기 작업을 큐 앞에 빠르게 추가할 수 있습니다. 예: 데이터베이스에서 데이터를 읽고 ListView 목록에 표시합니다.
네트워크 IO 작업이 아닌 경우:
HandlerThread는 단일 스레드 동기 대기열이므로 네트워크 IO 작업 처리에 적합하지 않습니다.
HandlerThread의 장단점
장점 : 여러 작업을 수행하기 위해 하나의 스레드만 시작할 수 있습니다.
단점 : 멀티태스킹이 지원되지만 HandlerThread는 동기식이며 동시성을 달성할 수 없습니다.
따라서 스레드 작업 중 하나를 실행하는 데 너무 오래 걸리면 후속 작업이 지연됩니다.
지침
HandlerThread 사용이
끝나면 quitSafe() 또는 quit() 메서드를 호출하여 스레드를 종료
해야 합니다 .
quitSafe()는 종료하기 전에 처리 중인 메시지가 처리될 때까지 기다립니다.
quit() 메시지 처리 여부에 관계없이 모든 콜백을 직접 제거합니다.