English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Premessa
Pochi giorni fa ho visto una domanda di intervista: Qual è la differenza tra Thread, Handler e HandlerThread? Questa domanda è interessante, per molte persone potrebbe essere familiare con Thread e Handler, che sono principalmente coinvolti nel meccanismo di messaggi di Android (Handler, Message, Looper, MessageQueue), vedi anche "Riassunto del meccanismo di messaggi di Android da Handler.post(Runnable r) - Esperienze e memorie"
Ma a cosa serve questo HandlerThread? È un Handler o un Thread? Sappiamo che l'Handler viene utilizzato per aggiornare l'UI in modo asincrono, più dettagliatamente, per comunicare tra thread, quando aggiorniamo l'UI è la comunicazione tra il thread secondario e il thread principale dell'UI. Quindi, se vogliamo comunicare tra thread secondari, come fare? Alla fine, anche questo può essere fatto utilizzando Handler+Thread (non raccomandato, richiede operazioni manuali su Looper), Google ha gentilmente encapsulato una classe per noi, ovvero il già menzionato: HandlerThread. (Per scenari multi-thread, ci sono anche encapsulamenti simili come AsyncTask)
Metodo di utilizzo
Vediamo prima come utilizzare HandlerThread:
Prima crea un HandlerThread e esegui start()
private HandlerThread mHandlerThread; ...... mHandlerThread = new HandlerThread("HandlerThread"); handlerThread.start();
Crea un Handler, utilizzando mHandlerThread.getLooper() per generare Looper:
final Handler handler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { System.out.println("ricevuto messaggio"); } });
Poi crea un thread secondario per inviare messaggi:
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000);//operazione di consumo di tempo simulata handler.sendEmptyMessage(0); } e.printStackTrace(); } } }).start();
Infine, non dimenticare di rilasciare in onDestroy per evitare le perdite di memoria:
@Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); }
Il risultato dell'esecuzione è molto semplice, ovvero stampare la stringa nella console: ricevuto messaggio
Principio
Nel processo di utilizzo intero non dobbiamo preoccuparci delle cose correlate a Handler, è sufficiente inviare messaggi, elaborare messaggi, e le cose correlate a Looper vengono lasciate al loro stesso processo di elaborazione. Vediamo ora il codice sorgente per capire come viene implementato, iniziamo con il costruttore:
public class HandlerThread extends Thread {}
HandlerThread è ancora una thread, cosa lo distingue da una thread comune?
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } ...... }
La risposta è che c'è un altro Looper, questo è il Looper esclusivo della sottolinea di thread, usato per estrarre e gestire i messaggi. Continuiamo a guardare il metodo run() della classe thread HandlerThread:
protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); // Genera Looper notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); // Metodo vuoto, chiamato dopo la creazione del Looper, può essere sovrascritto per logica personalizzata Looper.loop(); // Ciclo infinito, che continua a prendere messaggi dalla MessageQueue e a consegnarli al Handler mTid = -1; }
Principalmente si tratta di alcune operazioni su Looper, se lo facciamo noi stessi usando Handler+Thread, dobbiamo eseguire questa operazione. Vediamo anche il metodo getLooper():
public Looper getLooper() { if (!isAlive()) { return null; } // Se il thread è stato avviato, attendi fino a che il looper è stato creato. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } } } } return mLooper; }
Il metodo è semplice, aggiungendo un blocco di sincronizzazione, se è stato creato (isAlive() restituisce true) ma mLooper è vuoto, continua a attendere fino a che mLooper viene creato con successo, infine controlla il metodo quit, è degno di nota che ci sono due di essi:
public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; }
quitSafely è utilizzato per fermare i messaggi in coda o i messaggi in ritardo non elaborati. Dopo aver chiamato questo metodo, tutti questi messaggi saranno fermati.
Sommario
Il metodo di utilizzo di HandlerThread è piuttosto semplice, ma dobbiamo capire un punto fondamentale: se una thread deve elaborare messaggi, deve avere il proprio Looper, non è sufficiente creare un Handler per elaborare messaggi ovunque.
Se non si utilizza HandlerThread, è necessario chiamare manualmente i metodi come Looper.prepare() e Looper.loop().
Di seguito è riassunta la raccolta delle informazioni sulla relazione tra Thread, Handler e HandlerThread, ulteriori informazioni saranno aggiunte in seguito, grazie per il supporto della nostra community!
Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, il copyright è di proprietà del rispettivo autore, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, sei invitato a inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.