2012-10-19 17 views
6

Il mio requisito è quello di avere un thread che mantiene una connessione socket tra un dispositivo BlackBerry e un server e scambia comandi, simili a richieste e risposte.Classe BlackBerry equivalente a AsyncTask?

Il mio problema è che ho bisogno di avere questo thread in esecuzione in background e mantenere l'interfaccia utente disponibile per l'utente. Quindi, quando c'è un comando dal server, questo thread lo analizza e aggiorna l'interfaccia utente e anche se c'è un'azione da parte dell'utente BlackBerry, lo invia al server e il server a sua volta lo gestisce.

Ho sviluppato la stessa applicazione in Android utilizzando AsyncTask e funziona bene. Ma in BlackBerry, poiché non esiste una tale classe, ho usato l'opzione invokeLater(). La comunicazione funziona bene tra il server e il dispositivo BB, ma l'interfaccia utente è bloccata sul BlackBerry.

Qualcuno ha qualche idea su come farlo correttamente?

+2

vorrei solo usare una pianura thread Java vecchio ... – Lawrence

+0

Consumer/Problema del produttore: http://en.wikipedia.org/wiki/Producer-consumer_problem –

+0

In realtà mi piace molto questo approccio. Cercando di imitare l'API, trovo che più del mio codice può essere riusabile tra Android e BlackBerry. Ho fatto questo con alcune classi comuni. – Nate

risposta

12

Vishal è sulla strada giusta, ma un po 'di più è necessaria per corrispondere Android di AsyncTask. Poiché enumerazioni e generici non sono disponibili con Java 1.3 su BlackBerry, non è possibile abbinare perfettamente l'API Android.

Ma, si potrebbe fare qualcosa di simile (non testato ... questo è solo un punto di partenza per voi):

import net.rim.device.api.ui.UiApplication; 

public abstract class AsyncTask { 

    public static final int FINISHED = 0; 
    public static final int PENDING = 1; 
    public static final int RUNNING = 2; 

    private int _status = PENDING; 
    private boolean _cancelled = false; 
    private Thread _worker; 

    /** subclasses MUST implement this method */ 
    public abstract Object doInBackground(Object[] params); 

    protected void onPreExecute() { 
     // default implementation does nothing 
    } 
    protected void onPostExecute(Object result) { 
     // default implementation does nothing 
    } 
    protected void onProgressUpdate(Object[] values) { 
     // default implementation does nothing 
    } 
    protected void onCancelled() { 
     // default implementation does nothing 
    } 
    protected void onCancelled(Object result) { 
     onCancelled(); 
    } 

    public final int getStatus() { 
     return _status; 
    } 

    public final boolean isCancelled() { 
     return _cancelled; 
    } 

    public final boolean cancel(boolean mayInterruptIfRunning) { 
     if (_status == FINISHED || _cancelled) { 
      return false; 
     } else { 
      _cancelled = true; 
      if (mayInterruptIfRunning && _status == RUNNING) { 
       // NOTE: calling Thread.interrupt() usually doesn't work 
       // well, unless you don't care what state the background 
       // processing is left in. I'm not 100% sure that this is how 
       // Android's AsyncTask implements cancel(true), but I 
       // normally just cancel background tasks by letting the 
       // doInBackground() method check isCancelled() at multiple 
       // points in its processing. 
       _worker.interrupt(); 
      } 
      return true; 
     } 
    } 

    protected final void publishProgress(final Object[] values) { 
     // call back onProgressUpdate on the UI thread 
     UiApplication.getUiApplication().invokeLater(new Runnable() { 
      public void run() { 
       onProgressUpdate(values); 
      } 
     }); 
    } 

    private void completeTask(final Object result) { 
     // transmit the result back to the UI thread 
     UiApplication.getUiApplication().invokeLater(new Runnable() { 
      public void run() { 
       if (isCancelled()) { 
        onCancelled(result); 
       } else { 
        onPostExecute(result); 
       } 
       // TODO: not sure if status should be FINISHED before or after onPostExecute() 
       _status = FINISHED; 
      } 
     }); 
    } 

    public AsyncTask execute(final Object[] params) throws IllegalStateException { 
     if (getStatus() != PENDING) { 
      throw new IllegalStateException("An AsyncTask can only be executed once!"); 
     } else { 
      try { 
       onPreExecute(); 

       _worker = new Thread(new Runnable() { 
        public void run() { 
         try { 
          // run background work on this worker thread 
          final Object result = doInBackground(params); 
          completeTask(result); 
         } catch (Exception e) { 
          // I believe if Thread.interrupt() is called, we'll arrive here 
          completeTask(null); 
         } 
        } 
       }); 
       _status = RUNNING; 
       _worker.start(); 
      } catch (Exception e) { 
       // TODO: handle this exception 
      } 
     } 

     return this; 
    } 

} 

Inoltre, è importante tenere a mente le regole Threading per Android di AsyncTask, che si applicano a quanto sopra implementazione, anche:

regole threading ci sono alcune regole di threading che devono essere seguite f o questa classe per funzionare correttamente:

  • La classe AsyncTask deve essere caricata sul thread dell'interfaccia utente. Questo è fatto automaticamente da JELLY_BEAN.

  • L'istanza dell'attività deve essere creata su il thread dell'interfaccia utente.

  • execute (Params ...) deve essere richiamato sul thread dell'interfaccia utente.

  • Non chiamare suPreExecute(), onPostExecute (Risultato), doInBackground (Params ...), onProgressUpdate (Progresso ...) manualmente.

  • Il compito può essere eseguito solo una volta (un'eccezione viene generata se un seconda esecuzione è tentato.)

+0

Grazie mille Nate. Ha funzionato :) –

+1

@Nate +1 e alcune grandi cose di apprendimento per me. Grazie Nate –

+0

@VishalVyas, nessun problema. Hai decisamente avuto la giusta idea. E, ora che ho scritto qualcosa per questa risposta, inizierò a usarlo nelle app BlackBerry :) – Nate

4

È possibile creare una classe che estenda la mia implementazione della classe AsyncTask. Good Luck :)

Qui i metodi onPreExecute, onPostExecute vengono eseguiti sul thread dell'interfaccia utente e doInBackground viene chiamato sul thread di lavoro. Dal momento che onPreExecute, onPostExecute sono astratti, è possibile sovrascriverli e fornire la propria implementazione come mostrare e chiudere la finestra di dialogo di avanzamento.

La sequenza in cui i metodi get eseguito è 1) OnPreExecute 2) doInBackground 3) OnPostExecute

import net.rim.device.api.ui.UiApplication; 
import net.rim.device.api.ui.component.Dialog; 

public abstract class AsyncTask { 
    Runnable runnable; 
    Thread threadToRun; 

    public abstract void onPreExecute(); 

    public abstract void onPostExecute(); 

    public abstract void doInBackground(); 

    public void execute() { 
    try { 
     runnable = new Runnable() { 

      public void run() { 
       // TODO Auto-generated method stub 
       UiApplication.getUiApplication().invokeLater(
         new Runnable() { 

          public void run() { 
           // TODO Auto-generated method stub 
           onPreExecute(); 
          } 
         }); 

       doInBackground(); 

       UiApplication.getUiApplication().invokeLater(
         new Runnable() { 

          public void run() { 
           // TODO Auto-generated method stub 
           onPostExecute(); 
          } 
         }); 

      } 
     }; 

     threadToRun = new Thread(runnable); 
     threadToRun.start(); 
    } catch (Exception e) { 
     // TODO: handle exception 
     Dialog.alert("Async Error Occured. " + e.toString()); 
    } 
} 
} 
+0

Spero che questo aiuti. –

+2

Anche se questo è un buon inizio, ci sono un paio di problemi. (1) 'onPreExecute()' qui sopra non è garantito per l'esecuzione prima di 'doInBackground()' nella vostra implementazione, e quasi certamente non ** inizierà ** prima di 'doInBackground()'. (2) 'AsyncTask' di Android include anche un metodo per' publishProgress() 'durante l'elaborazione in background. – Nate

+0

@Nate Sarebbe grandioso se potesse spiegare perché non è garantito che 'onPreExecute()' non venga invocato prima di 'doInBackground()' in quanto mi aiuterà a migliorare questa implementazione. Ho usato questa implementazione in molti dei miei progetti di blackberry per mostrare un indicatore di avanzamento e chiuderlo quando il processo è completato. –

Problemi correlati