Informazioni sulla concorrenza su Android con HaMeR

1. Introduzione

Tutti coloro che cercano lo sviluppo di Android scopre l'importanza della concorrenza. L'unico modo per creare un'app reattiva è lasciare il thread UI il più libero possibile, lasciando che tutto il duro lavoro sia svolto in modo asincrono dai thread in background.

A causa del design di Android, la gestione dei thread utilizzando solo il java.lang.Threadjava.util.concurrent i pacchetti potrebbero essere davvero difficili. Usare i pacchetti di threading di basso livello con Android significa che devi preoccuparti di una sincronizzazione complicata per evitare condizioni di gara. Fortunatamente la gente di Google ha fatto il duro lavoro e ha creato alcuni ottimi strumenti per semplificare il nostro lavoro: AsyncTaskIntentServicecaricatoreAsyncQueryHandler e CursorLoader sono tutti utili, così come le classi HaMeR handler, Messaggio, e Runnable. Ci sono molte ottime opzioni tra cui scegliere, ognuna con i suoi pro e contro.

Molto è stato detto a proposito del AsyncTask oggetto, e molte persone lo usano come un pallottola d'argento soluzione per concorrenza su Android. È estremamente utile per operazioni brevi, facili da implementare e probabilmente l'approccio più popolare alla concorrenza su Android. Se vuoi saperne di più AsyncTask, controlla i seguenti post di Envato Tuts +.

  • Android From Scratch: operazioni in background

    Threading in qualsiasi linguaggio di programmazione o piattaforma è difficile, e Android non fa eccezione. In questo tutorial imparerai alcuni degli strumenti ...
    Paul Trebilcox-Ruiz
    SDK Android
  • Comprensione dei valori AsyncTask in 60 secondi

    Su Android, la classe AsyncTask viene comunemente utilizzata per eseguire operazioni su un thread in background. In questo video, ti mostro come funziona un AsyncTask e come tu ...
    Paul Trebilcox-Ruiz
    androide

però, AsyncTask non dovrebbe essere l'unico strumento sulla tua cintura degli attrezzi.

Per operazioni di lunga durata, problemi complessi di concorrenza o per ottenere maggiore efficienza in alcune situazioni, è necessario scegliere un'altra soluzione. Se hai bisogno di più flessibilità o efficienza rispetto a AsyncTask fornisce, è possibile utilizzare l'HaMeR (handler, Messaggio & Runnable) struttura.In questo tutorial esploreremo il framework HaMeR, uno dei più potenti modelli di concorrenza disponibili su Android, e impareremo quando e come usarlo. In un tutorial di follow-up, ti mostrerò come codificare un'applicazione per provare alcune possibilità di HaMeR.

La seguente sezione introdurrà l'importanza dei thread in background per il sistema Android. Se hai familiarità con questo concetto, sentiti libero di saltarlo e vai direttamente alla discussione del framework HaMeR nella sezione 3.

2. Reattività tramite thread in background

Quando viene avviata un'applicazione Android, il primo thread generato dal suo processo è il thread principale, noto anche come thread UI, che è responsabile della gestione dell'intera logica dell'interfaccia utente. Questo è il thread più importante di un'applicazione. È responsabile della gestione di tutte le interazioni dell'utente e anche del "collegamento" delle parti mobili dell'applicazione. Android lo prende molto seriamente, e se il tuo thread dell'interfaccia utente è bloccato a lavorare su un'attività per più di qualche secondo, l'app si bloccherà.

[Il thread dell'interfaccia utente] è molto importante perché è responsabile degli eventi di distribuzione per i widget dell'interfaccia utente appropriati, inclusi gli eventi di disegno. È anche il thread in cui l'applicazione interagisce con i componenti del toolkit dell'interfaccia utente Android (componenti dal android.widget e android.view pacchi). Di conseguenza, il thread principale viene anche chiamato il thread dell'interfaccia utente. - Processi e discussioni, Guida per gli sviluppatori Android

Il problema è che quasi tutto il codice in un'applicazione Android verrà eseguito sul thread dell'interfaccia utente per impostazione predefinita. Poiché le attività su un thread vengono eseguite in sequenza, ciò significa che l'interfaccia utente potrebbe "bloccarsi", non rispondere mentre sta elaborando un altro lavoro.

Le attività a esecuzione prolungata richiamate nell'interfaccia utente saranno probabilmente fatali per la tua app e verrà visualizzata una finestra di dialogo ANR (Application Not Responding). Anche le piccole attività possono compromettere l'esperienza dell'utente, quindi l'approccio corretto è quello di rimuovere il più lavoro possibile dal thread dell'interfaccia utente utilizzando thread in background. Come detto prima, ci sono molti modi per risolvere questo problema, e esploreremo il framework HaMeR, una delle soluzioni core fornite da Android per affrontare questa situazione.

3. Il quadro HaMeR

Il framework HaMeR consente ai thread in background di inviare messaggi o post di esecuzione al thread dell'interfaccia utente e a qualsiasi altro thread MessageQueue tramite i gestori. HaMeR si riferisce a handler, Messaggio, & Runnable. Ci sono anche altre importanti classi che funzionano insieme con HaMeR: Looper e MessageQueue. Insieme, questi oggetti sono responsabili di facilitare la gestione dei thread su Android, occupandosi della sincronizzazione e fornendo metodi semplici per i thread in background per comunicare con l'interfaccia utente e con altri thread.

Ecco come si integrano le classi nel framework HaMeR.

  • Looper esegue un loop di messaggi su un thread usando il MessageQueue.
  • MessageQueue contiene un elenco di messaggi che devono essere inviati dal Looper.
  • handler consente l'invio e l'elaborazione di Messaggio e Runnable al MessageQueue. Può essere usato per inviare ed elaborare messaggi tra thread.
  • Messaggio contiene una descrizione e dati che possono essere inviati a un gestore.
  • Runnable rappresenta un compito da eseguire.

Con il framework HaMeR, i thread possono inviare messaggi o pubblicare oggetti eseguibili su se stessi o sul thread dell'interfaccia utente. HaMeR promuove anche le interazioni thread in background tramite handler.

3.1. La classe dell'handler

handler è il cavallo di battaglia HaMeR. È responsabile dell'invio Messaggio (messaggio dati) e post Runnable (messaggio di attività) oggetti al MessageQueue associato a a Filo. Dopo aver consegnato le attività alla coda, il gestore riceve gli oggetti dal Looper ed elabora i messaggi al momento opportuno usando il handler associato ad esso.

UN handler può essere usato per inviare o pubblicare Messaggio e Runnable oggetti tra i thread, purché tali thread condividano lo stesso processo. Altrimenti sarà necessario creare una Inter Process Communication (IPC), una metodologia che supera lo scopo di questo tutorial.

Istanziare un gestore

UN handler deve sempre essere associato a a Looper, e questa connessione deve essere fatta durante la sua istanziazione. Se non fornisci un Looper al handler, sarà legato alla corrente Filo'S Looper.

// Il gestore utilizza il gestore del gestore del looper corrente di Thread = new Handler (); // Il gestore usa il Looper fornisce Handler handler = new Handler (Looper);

Tieni presente che a handler è sempre associato a a Looper, e questa connessione è permanente e non può essere modificata una volta stabilito. Tuttavia, a LooperLa discussione di 's può avere associazioni con multipli handlerS. È anche importante notare che a Looper deve essere attivo prima della sua associazione con a handler.

3.2. Looper e MessageQueue

Il lavoro cooperativo tra Looper e MessageQueue in un thread Java crea un ciclo di attività che vengono elaborate in sequenza. Tale ciclo manterrà il thread attivo mentre attende di ricevere più attività. Un thread può avere solo uno Looper e uno MessageQueue associato ad esso; tuttavia, possono esserci più gestori per ogni thread. I gestori sono responsabili dell'elaborazione delle attività in coda e ogni attività sa quale gestore è responsabile dell'elaborazione.

3.3. Preparare una discussione per HaMeR

L'interfaccia utente o thread principale è l'unico tipo di thread che per impostazione predefinita ha già un handler, un Looper, e a MessageQueue. Altri thread devono essere preparati con tali oggetti prima che possano lavorare con il framework HaMeR. Per prima cosa dobbiamo creare un Looper che include già un MessageQueue e collegalo al filo. Puoi farlo con una sottoclasse di Filo, come segue.

// Preparazione di un thread per HaMeR class LooperThread estende Thread public Handler mHandler; public void run () // aggiunta e preparazione di Looper Looper.prepare (); // l'istanza di Handler sarà associata a Looper di Thread mHandler = new Handler () public void handleMessage (Message msg) // process incoming messages here; // Avvio del ciclo della coda dei messaggi utilizzando Looper Looper.loop (); 

Tuttavia, è più semplice usare una classe helper chiamata HandlerThread, che ha un Looper e a MessageQueue costruito in un Java Filo ed è pronto a ricevere un gestore.

// La classe HandlerThread include una classe pubblica di Looper funzionante HamerThread estende HandlerThread // è sufficiente aggiungere il gestore Handler Private Handler; HamerThread pubblico (nome stringa) super (nome); 

4. Registrare i Runnables

Il Runnable è un'interfaccia Java che ha molti usi. Potrebbe essere inteso come un singolo compito da eseguire su a Filo. Ha un unico metodo che deve essere implementato, Runnable.run (), per eseguire l'operazione.

// Dichiarare un Runnable Runnable r = new Runnable () @ Override public void run () // l'attività va qui;

Ci sono più opzioni per pubblicare un Runnable a handler.

  • Handler.post (Runnable r): Aggiungi il Runnable al MessageQueue.
  • Handler.postAtFrontOfQueue (Runnable r): Aggiungi il Runnable nella parte anteriore del MessageQueue.
  • handler.postAtTime (Runnable r, long timeMillis): Aggiungi il Runnable sul MessageQueue essere chiamato in un momento specifico.
  • handler.postDelayed (Runnable r, long delay): Aggiungi il Runnable alla coda da chiamare dopo che è trascorso un determinato periodo di tempo.
// postare un Runnable su un gestore Handler handler = new Handler (); handler.post (new Runnable () @Override public void run () // task goes here);

È anche possibile utilizzare il gestore dell'interfaccia utente predefinito per pubblicare un Runnable chiamata Activity.runOnUiThread ().

// postare eseguibile utilizzando il gestore dell'interfaccia utente Activity.runOnUiThread (new Runnable () @Override public void run () // task da eseguire);

È importante tenere a mente alcune cose RunnableS. A differenza di Messaggio, un Runnable non può essere riciclato, una volta che il suo lavoro è finito, è morto. Poiché fa parte di un pacchetto Java standard, a Runnable non dipende da handler e può essere chiamato su uno standard Filo usando il Runnable.run () metodo. Tuttavia, questo approccio non ha nulla a che fare con il framework HaMeR e non condividerà nessuno dei suoi vantaggi.

5. Invio di messaggi

Il Messaggio oggetto definisce un messaggio contenente una descrizione e alcuni dati arbitrari che possono essere inviati ed elaborati tramite handler. Il Messaggio è identificato con un int definito su Message.what (). Il Messaggio può tenere due altri int argomenti e an Oggetto per memorizzare diversi tipi di dati.

  • Message.what: int identificando il Messaggio
  • Message.arg1: int argomento arbitrario
  • Message.arg2: int argomento arbitrario
  • Message.obj: Oggetto per memorizzare diversi tipi di dati  

Quando è necessario inviare un messaggio, invece di crearne uno da zero, l'approccio consigliato è quello di recuperare uno riciclato direttamente dal pool globale con il Message.obtain () o Handler.obtainMessage () comandi. Ci sono alcune versioni differenti di quei metodi che ti permettono di ottenere un Messaggio in base alle tue necessità.

Un uso comune di Handler.obtainMessage () è quando devi inviare un messaggio a un thread in background. Userai il handler associato a quel thread Looper ottenere un Messaggio e inviarlo al thread in background, come nell'esempio seguente.

int what = 0; String hello = "Hello!"; // Ottenimento del messaggio associato allo sfondo Thread Message msg = handlerBGThread.obtainMessage (what, hello); // Invio del messaggio allo sfondo Thread handlerBGThread.sendMessage (msg); 

Ci sono molti metodi interessanti su Messaggio classe, e ti consiglio di dare un'occhiata più da vicino alla documentazione.

5.1. invia messaggio() Opzioni

Allo stesso modo di come possiamo pubblicare Runnables, ci sono più opzioni da inviare MessaggioS:

  • Handler.sendMessage (messaggio msg): aggiungere un Messaggio al MessageQueue.
  • Handler.sendMessageAtFrontOfQueue (messaggio msg): aggiungere un Messaggio alla parte anteriore del MessageQueue.
  • Handler.sendMessageAtTime (messaggio msg, long timeInMillis): aggiungere un Messaggio alla coda in un momento specifico.
  • Handler.sendMessageDelayed (messaggio msg, long timeInMillis): aggiungere un Messaggio alla coda dopo che è trascorso un determinato periodo di tempo.

5.2. Gestione dei messaggi con il gestore

Il Messaggio oggetti spediti da Looper vengono elaborati dal gestore con il metodo Handler.handleMessage. Tutto ciò che devi fare è estendere il handler classificare e sovrascrivere questo metodo per elaborare i messaggi.

public class MessageHandler extends Handler @Override public void handleMessage (Message msg) switch (msg.what) // handle 'Hello' msg case 0: String hello = (String) msg.obj; System.out.println (ciao); rompere; 

6. Conclusione

Il framework HaMeR può aiutare a migliorare il codice concorrente dell'applicazione Android. Può sembrare confuso in un primo momento rispetto alla semplicità di un AsyncTask, ma l'apertura di HaMeR può essere un vantaggio, se usato correttamente. 

Ricorda:

  • Handler.post () i metodi vengono utilizzati quando i mittenti sanno quali operazioni eseguire.
  • Handler.sendMessage() i metodi vengono utilizzati quando il ricevitore sa quale operazione eseguire.

Per ulteriori informazioni sul threading in Android, potresti essere interessato al libro Efficient Android Threading: tecniche di elaborazione asincrona per applicazioni Android di Anders Goransson.

6.1. Qual'è il prossimo?

Nel prossimo tutorial, continueremo a esplorare il framework HaMeR con un approccio pratico, creando un'applicazione che mostri diversi modi di utilizzare questo framework di concorrenza Android. Creeremo questa app da zero, provando diverse possibilità come la comunicazione tra discussioni, parlando con il thread dell'interfaccia utente, oltre a inviare messaggi e post Runnables con ritardi. 

A presto!