Autore Topic: ScheduledExecutorService + Asynctask = thread safe?  (Letto 611 volte)

Offline crc_error

  • Utente junior
  • **
  • Post: 85
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    LG-P500
  • Sistema operativo:
    Windows 8, Ubuntu 12
ScheduledExecutorService + Asynctask = thread safe?
« il: 17 Luglio 2013, 18:59:58 CEST »
0
Ciao a tutti, sto usando uno scheduler per ripetere un asynctask ogni tot minuti.
Ho però un dubbio che il tutto non sia un pò troppo articolato e non sia thread safe, in particolare l'accesso nel "pre" e "postExecute" alla progressbar..

Il dubbio è il runnable che lancia l'async.. dovrei usare il runOnUiThread() e lanciare l'async da li?

Posto il codice sperando di non aver cannibalizzato troppo (l'async è bello lungo..)

Codice (Java): [Seleziona]
// =====================================================
// VARIABILI e ALTRO
// =====================================================

private AsyncTask<Bundle, Integer, Boolean> aggiornaMeteo;
private ProgressBar pbMeteo;

// =====================================================
// METODI DEL FRAGMENT
// =====================================================
       
@Override
public void onActivityCreated(Bundle savedInstanceState) {
        Bundle bnd = new Bundle();
        pbMeteo = (ProgressBar) mainView.findViewById(R.id.pbFragMeteo);
        // aggiunta valori al bundle
        attivaCiclicaMeteo(bnd);
       
}

// =====================================================
// METODI PRIVATI
// =====================================================
       
private void attivaCiclicaMeteo(Bundle bnd) {
        ciclicaMeteo = Executors.newScheduledThreadPool(1);
        Runnable meteo = new MeteoSingolo(bnd);
        ciclicaMeteo.scheduleAtFixedRate(meteo, 0, 900, TimeUnit.SECONDS);     
        Log.i(Utility.APP_NAME, "SERVIZIO POS: ciclica meteo attiva");
}

// =====================================================
// RUNNABLE e THREAD
// =====================================================

public class MeteoSingolo implements Runnable {
       
        Bundle toUse;
       
        public MeteoSingolo(Bundle bnd) {
                this.toUse = bnd;
        }

        @Override
        public void run() {
                if(aggiornaMeteo.getStatus() == null || aggiornaMeteo.getStatus() == AsyncTask.Status.FINISHED)                
                        aggiornaMeteo = new UpdateMeteo().execute(toUse);
        }
}


// =====================================================
// ASYNCTASK
// =====================================================               
       
private class UpdateMeteo extends AsyncTask<Bundle, Integer, Boolean> {

        @Override
        protected void onPreExecute() {
                pbMeteo.setProgress(0);
                pbMeteo.setVisibility(View.VISIBLE);
        }

        @Override
        protected Boolean doInBackground(Bundle... bnd) {
                if(this.isCancelled())
                        this.cancel(true);
                boolean stato = false;
                // ................
                // elaborazione...
                // ................
                publishProgress((int) ((i / (float) count) * 100));
               
                return stato;
        }
       
         protected void onProgressUpdate(Integer... progress) {
                pbMeteo.setProgress(progress[0]);
         }
       
        @Override
        protected void onPostExecute(Boolean nullo) {
                elabora.shutdown();
                if(nullo)
                        Toast.makeText(contesto, R.string.tstMeteoOk, Toast.LENGTH_LONG).show();
                else
                        Toast.makeText(contesto, R.string.tstMeteoNo, Toast.LENGTH_LONG).show();

                pbMeteo.setVisibility(View.GONE);
                pbMeteo.setProgress(0);
        }
}


Grazie mille in anticipo

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:ScheduledExecutorService + Asynctask = thread safe?
« Risposta #1 il: 17 Luglio 2013, 19:55:05 CEST »
0
L'asynctask deve essere effettivamente creato nel thread di UI, perchè da quello riceve il context. Può darsi che nel tuo caso avvenga perchè il runnable è una inner class dell'activity.

Per essere thread-safe è sicuramente thread-safe, altrimenti avresti un'eccezione cercando di cambiare l'UI da un thread diverso da quello di UI.

Unica cosa vagamente discutibile (nel senso di architettura dell'app) è quella di mettere codice che gestisce l'UI dentro thread pensati per azioni non di UI. Non perchè non sia sicuro, ma perchè la prima volta che cambi il layout, rischi di dover rimettere mano a tutti i file che in qualche modo accedono alla UI.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline crc_error

  • Utente junior
  • **
  • Post: 85
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    LG-P500
  • Sistema operativo:
    Windows 8, Ubuntu 12
Re:ScheduledExecutorService + Asynctask = thread safe?
« Risposta #2 il: 17 Luglio 2013, 20:40:58 CEST »
0
Grazie mille  :-)

E se creassi un costruttore per l'asynctask dove gli passo la progressbar? Una cosa così..
In questo modo potrei riutilizzare l'async anche per altri layout

Codice (Java): [Seleziona]
private class UpdateMeteo extends AsyncTask<Bundle, Integer, Boolean> {

       ProgressBar pbMeteo;
       
       public UpdateMeteo(ProgressBar mPb) {
          this.pbMeteo = mPb
       }

        @Override
        protected void onPreExecute() {
                pbMeteo.setProgress(0);
                pbMeteo.setVisibility(View.VISIBLE);
        }

etc, etc,