5

Ho 2 AsyncTasks in esecuzione in un frammento.
Gli AsyncTask sono definiti in una classe diversa e non in classi private interne del frammento.
Il problema che ho è che ora è venuto fuori che ho bisogno che AsyncTaskX attenda fino a quando AsyncTaskY ha finito il suo onPostExecute
Come posso risolvere questo?
Stavo pensando di usare un countdownlatch ma AsyncTaskY è in una classe diversa e non sono sicuro di quale sia il modo migliore per codificarlo?
C'è un modo per verificare se un AsyncTask è finito completamente?Come posso coordinare due attività in background?

Aggiornamento:
mi chiedevo è task.execute().get() ritorno dopo il onPostExecute?

Aggiornamento 2:
chiama CountDownLatch.countDown() dal thread dell'interfaccia utente al sicuro?

+1

È possibile passare la stessa istanza 'CountDownLatch' ai costruttori di entrambe le attività? –

+0

È possibile utilizzare le trasmissioni per notificare un destinatario nel frammento quando ciascuna di esse è completa. – dharms

+0

Riceverete una risposta dal primo AsyncTask. Sul callback del tuo First Async puoi semplicemente chiamare il secondo AsyncTask. – Ahmed

risposta

1

È davvero difficile determinarlo senza visualizzare il codice. Una soluzione sporca sarebbe aggiungere un valore booleano statico e quindi aggiungere un timer ricorsivo. Questa non è la migliore tecnica di programmazione, ma da quello che ho letto funzionerebbe sicuramente.

Creare un valore booleano statico in qualsiasi classe

static boolean onPostExecuteFinished; 

nel l'AsyncTask che deve essere finito prima impostare a true

ClassName.onPostExecuteFinished = true; 

Nella classe che ha bisogno di aspettare si effettua una ricorsiva metodo in attesa che finisca. Raccomando di usare un gestore.

public void nameOfRecursiveMethodHere() 
Handler handler = new Handler() 

handler.postDelated(new runnable........{ 
if (ClassName.onPostExecuteFinished) { 
//Great it is finished do what you need 
} else { 
//Not finished call this method again 
nameOfRecursiveMethodHere(); 
} 

}),(put how often you want it to check in milliseconds here); 
+0

Che funzionerebbe, ma non può essere una soluzione reale a qualcosa che dovrebbe essere un problema frequente, ovvero sincronizzare le attività asincrone – Jim

+0

onPostExecute è quando il AsyncTask è finito, quindi avvia il secondo AsyncTask nel primo onPostExecute? – fsebek

+0

Perderò la concorrenza. Penso che sia meglio serializzare solo ciò che deve essere seriale – Jim

1

Invece di utilizzare 2 AsyncTasks Vorrei suggerire di utilizzare RxJava e RxAndroid. La concorrenza è molto più facile lì.

Per esempio è possibile effettuare le seguenti operazioni per sincronizzare i lavori asincroni:

Observable<Object1> job1 = Observable.fromCallable(() -> yourCall2()); 
Observable<Object2> job2 = Observable.fromCallable(() -> yourCall2()); 

Observable.combineLatest(job1, job2, (object1, object2) -> yourMethod()) 
    .subscribeOn(Schedulers.io()) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(...); 

Questa è solo una piccola, ad esempio incompleta ma dovrebbe mostrare come ottenere ciò che si desidera. Ho usato Lambda Expressions per abbreviare il codice. Questo viene fatto usando Retrolambda. È possibile ottenere lo stesso con l'operatore zip.

1

Come ha commentato @ Andy-Turner, è possibile utilizzare un CountDownLatch, inoltre è possibile utilizzare un semaforo per segnalare l'esecuzione di un'attività da un'altra.

prega di consultare questo link: http://tutorials.jenkov.com/java-concurrency/semaphores.html

+0

Posso segnalare sul latch cioè 'countDown' dal thread dell'interfaccia utente? – Jim

+0

domanda interessante :) ma perché dovresti farlo? se è necessario sincronizzare le due attività asincrone sul livello del thread dell'interfaccia utente, è possibile implementarlo con i ricevitori broadcast o gli osservatori del contenuto. non c'è bisogno di introdurre più complessità con i metodi di sincronizzazione di Java. –

+0

No. AsyncTaskX è in esecuzione nel thread in background in 'doInBackground' e ad un certo punto necessita di qualcosa che sia pronto * dopo * AsyncTaskY ha terminato il suo' onPostExecute'. Quindi chiama 'countDown' da' onPostExecute' di AsyncTaskY in modo che 'AsyncTaskX' continui la sicurezza' doInBackgound'? – Jim

1

AsyncTasks vengono eseguiti in modo seriale su un singolo thread in background (from API 11).

un piccolo test:

private static class AsyncTaskX extends AsyncTask<Void, Void, Void>{ 
    @Override 
    protected Void doInBackground(Void... params) { 
     for (int i = 0; i < 10; i++){ 
      Log.i("test order", "ping X "+ i); 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     return null; 
    } 
} 

private static class AsyncTaskY extends AsyncTask<Void, Void, Void>{ 
    @Override 
    protected Void doInBackground(Void... params) { 
     for (int i = 0; i < 10; i++){ 
      Log.i("order", "ping Y" + i); 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     return null; 
    } 
} 

Logs:

test order: ping X 0 
test order: ping X 1 
test order: ping X 2 
test order: ping X 3 
test order: ping X 4 
test order: ping X 5 
test order: ping X 6 
test order: ping X 7 
test order: ping X 8 
test order: ping X 9 
order: ping Y0 
order: ping Y1 
order: ping Y2 
order: ping Y3 
order: ping Y4 
order: ping Y5 
order: ping Y6 
order: ping Y7 
order: ping Y8 
order: ping Y9 

Finché lavoratore in esecuzione può bloccare gli altri.

task.execute(). Get() ritornerà prima di onPostExecute e bloccherai il thread dell'interfaccia utente.

Controllare le informazioni generali su processes and threads and some gotchas.

Anche il tempo di esecuzione è importante, perché AsyncTask deve essere utilizzato solo per attività/operazioni che richiedono pochi secondi.

+0

AsyncTaskX e AsyncTaskY condividono un 'CountDownLatch'. Per entrambi li istanziamo e chiamiamo 'execute'. In AsyncTaskX faccio un po 'di lavoro nel 'doInBackground' e nella stessa funzione chiamo' await' su CountDownLatch. Quindi a quel punto il thread si blocca.In AsyncTaskY faccio un po 'di lavoro nel 'doInBackground', poi passo a' onPostExecute' dove finalmente chiamo 'countDown' sullo stesso conto alla rovescia che AsyncTaskX sta aspettando. ** Domanda: ** Perché non ottengo un deadlock se i task asincroni vengono eseguiti in serie dallo stesso thread? – Jim

+0

Puoi condividere il tuo codice? –

+0

Il codice è banale. Basta passare un CountDownLatch a 2 AsyncTasks e chiamare execute. L'unica spiegazione che posso dare è che ottengo l'AsyncTaskY programmato prima di AsyncTaskX costantemente – Jim

Problemi correlati