Se avete provato l’app presentata nel tutorial precedente, forse vi sarete accorti di un difetto: mentre viene stabilita la connessione Bluetooth con il dispositivo e viene inviato il messaggio, l’interfaccia grafica dell’applicazione non risponde. Il motivo è semplice: molti metodi utilizzati sono blocking, ovvero fermano l’esecuzione del processo che li chiama finché non ottengono un risultato (o un timeout).
Se ad esempio utilizziamo il metodo read() per leggere dati da un socket, tale metodo fermerà l’esecuzione del processo finché un dato non è disponibile!
Per risolvere il problema, dobbiamo creare una applicazione multitasking, ovvero formata da più processi con esecuzione indipendente.
Threads e GUI
Per semplificare, una applicazione può essere formata da uno o più processi (thread), eseguiti dal S.O. Android in parallelo. Le applicazioni più semplici, come quelle degli esempi precedenti, hanno un unico thread, chiamato main thread. Questo thread ha, tra gli altri, il compito di gestire i componenti (testo, immagini, pulsanti…) che compongono l’interfaccia (GUI) dell’applicazione.
La prima regola da tenere sempre in mente quando si lavora ad applicazioni multithread è infatti che solo il main thread può modificare l’intefaccia grafica:
Questa regola da spesso problemi ai programmatori: pensate al caso in cui un secondo thread riceve dati dal socket Bluetooth: probabilmente alla ricezione di determinati comandi, l’interfaccia grafica deve essere aggiornata di conseguenza…
La soluzione normalmente suggerita è di chiedere al thread principale di effettuare tale aggiornamento… io invece voglio mostrarvi un approccio alternativo, che si basa sull’uso dell’oggetto AsyncTask.
AsyncTask
L’oggetto AsyncTask è stato pensato per gestire in maniera semplice dei tasks che devono eseguiti in background e che devono interagire con l’intefaccia grafica dell’applicazione.
Il suo vantaggio è che, in maniera trasparente per il programmatore, ha alcuni metodi che vengono eseguiti nel GUI (main) thread e altri che invece vengono eseguiti in un thread separato.
Il programmatore può quindi sfruttare i metodi eseguiti nel GUI thread per aggiornare l’interfaccia e quelli nel secondo thread per le operazioni in background (ad es. per ricevere/inviare dati attraverso il socket):
Vediamo i metodi nel dettaglio:
[checklist]
- onPreExecute() – GUI – eseguito appena prima dell’inizio delle attività in background, può essere utile per visualizzare un avviso (animazione, messaggio…) che l’operazione richiesta è in esecuzione
- doInBackground() – background – metodo principale che viene eseguito in un thread separato
- publishProgress() – background – metodo, normalmente chiamato da doInBackground(), che serve per notificare un “progresso” nell’esecuzione del task
- onProgressUpdate() – GUI – metodo, chiamato da publishProgress(), che può aggiornare l’intefaccia grafica ricevendo il “progresso” del task in background
- onPostExecute() e onCancelled() – GUI – metodi eseguiti alla fine del task (o alla sua cancellazione)
[/checklist]
Nella prossima pagina vedremo come mettere tutto questo in pratica in una applicazione Android…
very good luca, thanks!
waiting the next.
Hi Luca,
Android coding is not simple.
I have developed pfodApp that does all the Android stuff for you. Lets you display menus and screens from your Arduino by means of simple text strings.
Take a look at http://www.pfod.com.au for all the details.
Hi Luca
Great example, thank you !
Would you recommend using this method to send/receive bluetoothdata from different activities within an app ??
If so how would you modify your code to work ?
Hi! My suggestion is to have only ONE “manager” that performs all the communication tasks and dispatches the messages to the different activities
GRANDE GIOVE !!!
MITICO LUCA !
Funziona e non ho più gli errori in Eclipse.
Questo era lo scoglio da superare per avere il punto di partenza
interattivo con la macchina che monta l’ HC-06.
Ora è una passeggiata nel parco !
Grazie.
Riciao.
Non ho capito come mai l’ XML per l’UI è
nel Fragment_main anziché nel activity_main
e funziona ugualmente….
Cos’è che non so ?
Grazie
Mauro
Ciao Luca !
Non riesco a cancellare il contenuto di tvResponse. Ho implementato un pulsante per pulire il contenuto dalle risposte della macchina via BT ma vorrei che a piacimento si potesse cancellare.
Ti ringrazio per la collaborazione.
Mauro