Comprendere Android Core: Looper, Handler e HandlerThread

Comprendere Android Core: Looper, Handler e HandlerThread

Questo articolo copre Android Looper, Handler e HandlerThread. Questi sono tra gli elementi costitutivi del sistema operativo Android.

Nella mia esperienza personale, li ho usati in un contesto molto limitato fino a poco tempo fa. Il mio caso d’uso riguardava l’invio di attività al thread principale/ui, principalmente per aggiornare l’interfaccia utente da qualsiasi altro thread. Gli altri aspetti dell’operazione multi-threaded sono stati gestiti tramite modi alternativi come ThreadPoolExecutor, IntentService e AsyncTask.

Il MultiThreading e l’esecuzione delle attività sono soggetti vecchi. Java stesso ha java.util.pacchetto simultaneo e Fork/Join framework per facilitarlo. Diverse librerie sono state scritte per semplificare le operazioni asincrone. RxJava è la libreria più popolare oggi per la programmazione reattiva e la progettazione di un’applicazione asincrona.

Quindi, perché sto scrivendo sulla vecchia scuola?

Looper, Handler, e HandlerThread sono il modo in cui Android risolve i problemi della programmazione asincrona. Non sono vecchia scuola, ma una struttura ordinata su cui è costruito un complesso framework Android.

Per i nuovi sviluppatori, si consiglia vivamente di comprendere i principi alla base di loro e uno esperto dovrebbe rivisitare questo argomento per ricordare i dettagli minori.

Ho anche creato un video tutorial per questo argomento, e consiglio vivamente di guardarlo. Clicca qui per guardare ora.

Casi d’uso:

  1. Il thread principale in Android è costruito con un Loopere Handlers. Quindi, la comprensione di esso è essenziale per creare un’interfaccia utente reattiva sbloccata.
  2. Gli sviluppatori che scrivono librerie non possono permettersi di utilizzare librerie di terze parti a causa delle dimensioni della libreria. Quindi, per loro, l’opzione migliore è utilizzare la risorsa disponibile esistente. Scrivere la propria soluzione potrebbe non sempre ottenere quel livello di efficienza e ottimizzazione.
  3. Lo stesso argomento può essere fatto anche per le aziende/individui che spediscono SDK. I client possono avere varie implementazioni, ma tutti condivideranno le comuni API del framework Android.
  4. Comprenderli completamente migliorerà la capacità di seguire l’SDK di Android e le classi di pacchetti in generale.

Iniziamo l’esplorazione/revisione con un questionario.

Mi aspetto che il lettore abbia la conoscenza di base dei thread java. Se avete bisogno, quindi ottenere una rapida panoramica di thread java e Runnable.

Qual è il problema con il thread java?

I thread Java sono monouso e muoiono dopo aver eseguito il metodo run.

Possiamo migliorare su di esso?

Il filo è un’arma a doppio taglio. Possiamo accelerare l’esecuzione distribuendo le attività tra i thread di esecuzione, ma possiamo anche rallentarlo quando i thread sono in eccesso. La creazione di thread di per sé è un overhead. Quindi, l’opzione migliore è avere un numero ottimale di thread e riutilizzarli per l’esecuzione delle attività.

Modello per la riusabilità del filo:

  1. Il thread viene mantenuto vivo, in un ciclo tramite il metodo run().
  2. L’attività viene eseguita in serie da quel thread e viene mantenuta in una coda (MessageQueue).
  3. Il thread deve essere terminato al termine.

Qual è il modo di farlo di Android?

Il modello di cui sopra è implementato in Android tramite Looper, Handler e HandlerThread. Il sistema può essere visualizzato come un veicolo come nella copertina dell’articolo.

  1. MessageQueue è una coda che ha attività chiamate messaggi che dovrebbero essere elaborati.
  2. Handleraccoda l’attività in MessageQueue usando Looper e li esegue anche quando l’attività esce da MessageQueue.
  3. Looper è un worker che mantiene vivo un thread, esegue il loop di MessageQueue e invia messaggi al corrispondente handler da elaborare.
  4. Infine Thread viene terminato chiamando il metodo quit() di Looper.

Un thread può avere un solo Looper unico e può avere molti gestori unici ad esso associati.

Creazione di Looper e MessageQueue per un thread:

Un thread ottiene un Looper e MessageQueue chiamando Looper.prepare() dopo la sua esecuzione. Looper.prepare() identifica il thread chiamante, crea un oggetto Looper e MessageQueue e associa thread a loro nella classe di archiviazione ThreadLocal. Looper.loop() deve essere chiamato per avviare il looper associato. Allo stesso modo, looper deve essere terminato esplicitamente tramite looper.quit().

class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; Looper.loop(); } }

Creazione del gestore per un thread:

Un Handler viene implicitamente associato al thread che lo istanzia tramite il thread Looper, ma possiamo legarlo esplicitamente a un thread passando il thread loopernel costruttore del Handler.

handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};

L’invio di messaggi al MessageQueue tramite Handler può essere fatto da due modalità:

  1. Message: È una classe che definisce vari metodi utili per gestire i dati dei messaggi. Per inviare un oggetto impostiamo la variabile obj.
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);

Una panoramica dettagliata della classe Message può essere trovata qui: https://developer.android.com/reference/android/os/Message.html

Runnable: Un runnable può anche essere pubblicato nel MessageQueue. Es: pubblicazione ed esecuzione di un’attività nel thread principale.

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});

Nell’esempio precedente, creiamo un Handler e forniamo Looper associato al thread principale. Questo associa questo gestore al thread principale. Quando pubblichiamo Runnable, viene messo in coda nel thread principale MessageQueue e quindi eseguito nel thread principale.

Il gestore è in grado di manipolare i messaggi in un’ampia varietà di modi, che possono essere trovati qui: https://developer.android.com/reference/android/os/Handler.html

Creare un proprio thread e fornire Lopper e MessageQueue non è il modo giusto per affrontare il problema. Quindi, Android ha fornito HandlerThread (sottoclasse di Thread) per semplificare il processo. Internamente fa le stesse cose che abbiamo fatto ma in modo robusto. Quindi, usa sempre HandlerThread.

Uno dei modi per creare HandlerThread è sottoclassarlo e la maggior parte delle volte utilizzerai questo metodo.

private class MyHandlerThread extends HandlerThread { Handler handler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { handler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; }}

Nota: Abbiamo istanziato il Gestore quando viene chiamato onLooperPrepared(). Quindi, quel Handler può essere associato a quel Looper.

  1. Looper viene preparato solo dopo HandlerThread start() viene chiamato cioè dopo che il thread è in esecuzione.
  2. A Handler può essere associato a HandlerThread, solo dopo che è stato preparato Looper.

Altro modo per creare HandlerThread:

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

Nota: HandlerThread deve chiamare myHandlerThread.quit() per liberare le risorse e interrompere l’esecuzione del thread.

Suggerirei di praticare i codici di cui sopra, in modo da poter cogliere i loro piccoli dettagli.

Ho creato un progetto di esempio per la simulazione dell’ufficio postale. L’ufficio postale è costruito su HandlerThread e i clienti comunicano con l’aiuto dell’ufficio postale. Una classe Simulator crea pochi Bot client e delega la loro comunicazione a MainActivity, che la rende in un feed live.

Il link a questo esempio

Ho anche creato un video tutorial per questo argomento, e consiglio vivamente di guardarlo. Clicca qui per guardare ora.

Inoltre, diventiamo amici su Twitter, Linkedin, Github e Facebook.

Imparare è un viaggio, impariamo insieme!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.