I callback si verificano sul thread principale (UI)?

Esistono molte API Android SDK in cui sono registrati i gestori di callback. Per un esempio concreto, con MediaPlayer è ansible impostare un callback onCompletionListener. Questi callback saranno chiamati dal thread principale (UI)? Se la risposta è “dipende”, quindi sto cercando alcune regole generali per quali callback saranno chiamati dal thread principale rispetto ad un altro thread. La documentazione SDK non sembra scriverlo. (Forse l’ho perso.)

Sembra importante saperlo, perché se sono garantito i richiami del thread principale, allora posso saltare la sincronizzazione dei thread sui dati condivisi tra diversi punti nel codice. Se sono costretto a essere pessimista per ignoranza, allora devo scrivere un codice di blocco di sincronizzazione extra e preoccuparmi di deadlock, integrità dei dati e prestazioni ridotte.

Un caso in cui Android chiamerà il tuo codice su un altro thread sarà se creerai un servizio remoto, esposto tramite AIDL: quei metodi AIDL verranno chiamati su un thread di binder, non il thread dell’applicazione principale.

Tuttavia, questa è l’eccezione. Come hanno notato gli altri, la stragrande maggioranza di questi sono chiamati sul thread dell’applicazione principale.

In caso di dubbi è ansible utilizzare Log.i("TAG", Thread.currentThread().getName()); e vedi 🙂

Nella mia esperienza, tali richiamate tornano sempre su un thread non dell’interfaccia utente. Hai provato Activity.runOnUiThread() per assicurarti che il tuo codice venga eseguito sul thread dell’interfaccia utente? Continueresti a fare il colpo perché ci vuole più tempo per eseguire questo codice, ma eviterai alcuni dei problemi più comuni con la sincronizzazione dei thread.

In generale, i callback si verificano nel thread in cui è in esecuzione l’evento. Se si registra una richiamata e si avvia qualcosa in esecuzione su un thread non dell’interfaccia utente, la callback verrà eseguita sul thread non dell’interfaccia utente. Tuttavia, Android non andrà a creare nuovi thread in background da solo.

Tutti gli eventi relativi all’interfaccia utente devono essere presenti nel thread dell’interfaccia utente, pertanto è ansible verificare che i callback del gestore di clic, ecc. Si verifichino sul thread dell’interfaccia utente.

Come ha sottolineato Aaron C, puoi usare Activity.runOnUiThread per forzare le cose a verificarsi lì.

Inoltre, AsyncTask può essere molto utile per fare un lavoro rapido in background, in cui è necessario un passo di completamento per essere sicuri di essere sul thread uI.

modifica: esempio dai commenti.

 public void MyWorker { private OnCompleteListener onCompleteListener; public void setOnCompleteListener(OnCompleteListener onCompleteListener) { this.onCompleteListener = onCompleteListener; } public void doWork() { // do lots of work here onCompleteListener.onComplete(); } } // somewhere in my Activity public void onCreate() { final MyWorker worker = new MyWorker(); worker.setOnCompleteListener(new OnCompleteListener() { ... }); new Thread(new Runnable() { public void run() { worker.doWork(); } }).start(); } 

In questo esempio, il “callback” onComplete verrà eseguito dal thread non UI. Il thread uscirà dopo il completamento di Completo.

Un’altra eccezione è il Quando si utilizza WebView. Quando javascript chiama una funzione Java, tale invocazione non avverrà nel thread principale

Qualcosa di simile si presentò quando stavo lavorando su Location APIs. Come sappiamo, forniamo una richiamata per i servizi di localizzazione, in modo da ricevere una notifica una volta acquisita una posizione. Quindi stavo facendo qualcosa in questo callback che impiegava molto tempo come usare le API di Geocoder.

Prima di ciò ero sotto impressione, questo callback sarebbe stato chiamato da un altro thread e quindi non sarebbe stato eseguito sul thread principale dell’interfaccia utente. Ma posso vedere, non è il caso.

Quindi, qualsiasi codice che scrivo in questo listener verrà eseguito sul thread principale.

Ora quello che non capisco è come riescono a farlo, è usando una funzione standerd runOnUIThread() ???