Einführung
HandlerThread
erbt von
Thread
und kapselt
Looper intern
. Nach dem Aufruf
der Methode handlerThread.start()
werden intern ein
Looper
und
eine MessageQueue erstellt .Wir
instanziieren einen Handler
über dieses
Looper- Objekt und können diesen
Handler dann in anderen Threads verwenden .
1. Verwenden Sie die herkömmliche Thread + Handler-Methode, um die Kommunikation zwischen Threads zu realisieren
Wir müssen das Looper-Objekt selbst implementieren und dann ein Handler-Objekt in der Looper-Schleife erstellen, um die Handler-Nachricht zu erhalten und die entsprechende Aufgabe auszuführen.
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. Verwenden Sie HandlerThread, um die Kommunikation zwischen Threads zu realisieren
Erstellen Sie einfach zuerst eine
HandlerThread-
Instanz, rufen Sie dann
handlerThread.start() auf, um ein
Looper- Objekt
zu erstellen ,
rufen Sie dann das Looper- Objekt in HandlerThread über handlerThread.getLooper() ab und erstellen Sie unseren Handler basierend auf diesem Looper -Objekt, um die Sub-Threads Business zu verarbeiten Logik.
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);
// 处理消息,在子线程调用,所以要在这执行耗时任务
}
};
Realisierungsprinzip
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;
}
}
Priorität Priorität in HandlerThread
Weisen Sie dem
HandlerThread- Thread
vernünftigerweise die Priorität zu und optimieren Sie den Thread bis zu einem gewissen Grad.
Seine Standardpriorität ist:
process.THREAD_PRIORITY_DEFAULT
, dessen Wert
"0" ist
.
Der Wertebereich der Priorität ist "-20 bis 19", je kleiner der Wert, desto höher die Priorität. Threads mit höherer Priorität erhalten mehr CPU-Ressourcen und umgekehrt.
Es ist jedoch nicht erforderlich, für HandlerThread eine so hohe Priorität
wie für einen Worker-Thread
festzulegen , daher müssen wir eine angemessene Prioritätsstufe entsprechend unseren Anforderungen festlegen.
HandlerThread-Verwendungsszenarien
Da es Looper
kapselt
, gehört es zur
Thread + Looper-
Szene. Führen Sie zeitaufwändige Aufgaben und Multitasking-Operationen in Unterthreads aus.
Für lokale IO-Operationen :
HandlerThread kann verwendet werden, um lokale E/A-Lese- und Schreibvorgänge zu verarbeiten, da die meisten lokalen E/A-Vorgänge Millisekunden dauern, sodass für HandlerThread, eine Form von Einzelthread + Warteschlange, keine Blockierung auftritt. Wir können auch die Methode postAtFrontQueue() verwenden, um die lokale E/A zu lesen, wodurch die Leseoperation schnell zur Ausführung an den Anfang der Warteschlange gestellt werden kann. Zum Beispiel: Daten aus der Datenbank lesen und in der ListView-Liste anzeigen.
Nicht für Netzwerk-IO-Operationen:
Da HandlerThread eine synchrone Singlethread-Warteschlange ist, ist sie nicht für die Verarbeitung von Netzwerk-E/A-Vorgängen geeignet.
Vor- und Nachteile von HandlerThread
Vorteile : Es kann nur ein Thread gestartet werden, um mehrere Aufgaben auszuführen.
Nachteile : Obwohl Multitasking unterstützt wird, ist HandlerThread synchron und kann keine Parallelität erreichen.
Wenn also die Ausführung einer der Thread-Aufgaben zu lange dauert, werden nachfolgende Aufgaben verzögert.
Vorsichtsmaßnahmen
Wenn
der HandlerThread mit der Verwendung fertig ist, müssen Sie seine
Methode quitSafe() oder quit()
aufrufen, um den Thread zu beenden.
quitSafe() wartet darauf, dass die verarbeitete Nachricht verarbeitet wird, bevor es beendet wird;
quit() entfernt alle Rückrufe direkt, unabhängig davon, ob die Nachricht verarbeitet wird oder nicht.