2012-03-28 7 views
14

Non ho trascorso molto tempo a lavorare con AsyncTasks in Android. Sto cercando di capire come passare le variabili da e verso la classe. La sintassi qui:Come passare le variabili dentro e fuori AsyncTasks?

class MyTask extends AsyncTask<String, Void, Bitmap>{ 

    // Your Async code will be here 

} 

è un po 'di confusione con la sintassi di < > sulla fine della definizione di classe. Non ho mai visto prima quel tipo di sintassi. Sembra che mi sia limitato a passare solo un valore nello AsyncTask. Sono errato nell'assumere questo? Se devo ancora passare, come faccio?

Inoltre, come si restituiscono i valori da AsyncTask?

Si tratta di una classe e quando si desidera utilizzarlo si chiamano new MyTask().execute() ma il metodo effettivo si utilizza nella classe è doInBackground(). Allora, dove restituisci qualcosa?

+0

probabilmente si dovrebbe vedere alcuni esempi e documentazione Android per questo per ottenere una migliore idea. –

+0

Ho, il documento non dice nulla sul passare più oggetti su AsyncTask. –

+0

Mi sono appena reso conto che dal momento che è una classe che probabilmente posso semplicemente creare membri pubblici e impostare quei membri a quello che voglio prima, '.execute()' ... Penso che funzionerà. –

risposta

42

Nota: tutte le informazioni di seguito sono disponibili sugli sviluppatori Android AsyncTask reference page. L'intestazione Utilizzo ha un esempio. Dai un'occhiata anche allo Painless Threading Android Developers Blog Entry.

Dai uno sguardo allo the source code for AsynTask.


La divertente notazione < > consente di personalizzare l'attività Async. Le parentesi sono utilizzate per aiutare a implementare generics in Java.

Ci sono 3 parti importanti di un compito che è possibile personalizzare:

  1. Il tipo di parametri passati in - qualsiasi numero che si desidera
  2. Il tipo per quello che si utilizza per aggiornare la barra di avanzamento/indicatore
  3. il tipo per quello che il ritorno una volta finito con il compito di sfondo

E ricordate, che una di queste può essere interfacce. Ecco come puoi passare in più tipi sulla stessa chiamata!

Disponete i tipi di queste 3 cose nelle parentesi angolari:

<Params, Progress, Result> 

Quindi, se avete intenzione di passare in URL s e utilizzare Integers per aggiornare i progressi e restituire un valore booleano che indica il successo si può scrivere:

public MyClass extends AsyncTask<URL, Integer, Boolean> { 

in questo caso, se si sta scaricando Bitmap per esempio, si sarebbe gestendo ciò che si fa con le bitmap sullo sfondo. Si potrebbe anche solo restituire una HashMap di Bitmap se lo si desidera. Ricorda inoltre che le variabili membro che usi non sono limitate, quindi non sentirti troppo legato da parametri, progresso e risultato.

Per avviare un AsyncTask è necessario istanziarlo e quindi execute in sequenza o in parallelo. Nell'esecuzione è dove passi le tue variabili. Puoi passarne più di uno.

Si noti che si non chiamare doInBackground() direttamente. Questo perché così facendo si interrompe la magia di AsyncTask, ovvero che doInBackground() viene eseguito in un thread in background. Chiamandolo direttamente così com'è, lo farebbe girare nel thread dell'interfaccia utente. Quindi, invece, dovresti usare un modulo di execute(). Il lavoro di execute() consiste nel dare il via allo doInBackground() in un thread in background e non nel thread dell'interfaccia utente.

Lavorare con il nostro esempio dall'alto.

... 
myBgTask = new MyClass(); 
myBgTask.execute(url1, url2, url3, url4); 
... 

onPostExecute sparerà quando tutti i compiti da eseguire sono fatto.

myBgTask1 = new MyClass().execute(url1, url2); 
myBgTask2 = new MyClass().execute(urlThis, urlThat); 

Avviso come si può passare più parametri a execute() che passa il parametro più a doInBackground(). Questo è attraverso l'uso di String.format(...). Molti esempi mostrano solo l'estrazione dei primi parametri usando params[0], ma si dovrebbe make sure you get all the params. Se si sta passando in URL questo sarebbe (preso dall'esempio AsynTask, ci sono diversi modi per farlo):.

// This method is not called directly. 
// It is fired through the use of execute() 
// It returns the third type in the brackets <...> 
// and it is passed the first type in the brackets <...> 
// and it can use the second type in the brackets <...> to track progress 
protected Long doInBackground(URL... urls) 
{ 
     int count = urls.length; 
     long totalSize = 0; 

     // This will download stuff from each URL passed in 
     for (int i = 0; i < count; i++) 
     { 
      totalSize += Downloader.downloadFile(urls[i]); 
      publishProgress((int) ((i/(float) count) * 100)); 
     } 

     // This will return once when all the URLs for this AsyncTask instance 
     // have been downloaded 
     return totalSize; 
} 

Se avete intenzione di fare più attività bg, poi si vuole considerare che i suddetti myBgTask1 e myBgTask2 chiamate saranno effettuate in sequenza questo è grande se una chiamata dipende dall'altra, ma se le chiamate sono indipendenti, ad esempio si sta scaricando più i maghi, e non si cura quali arriva prima - allora si può fare i myBgTask1 e myBgTask2 chiamate in parallelo con il THREAD_POOL_EXECUTOR:

myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2); 
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat); 

Nota:

Esempio

Ecco un esempio AsyncTask che può prendere tutti i tipi che vuoi sullo stesso comando execute().La limitazione è che ogni tipo deve implementare la stessa interfaccia:

public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void> 
{ 
    public static interface BackgroundTodo 
    { 
     public void run(); 
    } 

    @Override 
    protected Void doInBackground(BackgroundTodo... todos) 
    { 
     for (BackgroundTodo backgroundTodo : todos) 
     { 
      backgroundTodo.run(); 

      // This logging is just for fun, to see that they really are different types 
      Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString()); 
     } 
     return null; 
    } 
} 

ora si può fare:

new BackgroundTask().execute(this1, that1, other1); 

Dove ognuno di questi oggetti è un tipo diverso! (che implementa la stessa interfaccia)

+0

Molto completo, grazie. Sebbene stavo cercando un modo per passare più tipi all'attività. –

+0

@Jakobud - sì, il problema è che un supertipo non può implementare un carattere jolly ('?'). Tuttavia, ciò che farei invece è creare un AsyncTask per ogni tipo. Poiché probabilmente ci sarebbe la duplicazione del codice, è possibile creare una classe base comune da cui ereditare. Inoltre, * potresti * passare semplicemente in un vecchio 'Object' e usare' instanceof' per lanciare in modo appropriato ... tuttavia, probabilmente questa non è una buona soluzione, dal momento che stai combattendo Java in quel momento. - Infine, puoi impostare i parametri come 'Void' e utilizzare invece i campi membri personalizzati. Questi potrebbero essere passati all'oggetto usando un metodo diverso per ogni tipo. –

+0

Puoi semplicemente creare un costruttore per AsynTask che accetta i parametri che vuoi? O questa classe non funziona davvero in quel modo? La soluzione che sto cercando in questo momento sembra funzionare bene è creare membri di classe pubblica e impostare quei membri a qualcosa dopo aver creato AsyncTask ma prima di '.execute()'. È un approccio sbagliato? Sembra funzionare bene finora ... –

2

Poiché è possibile passare la matrice di oggetti nella parentesi quadra, è il modo migliore per passare i dati in base ai quali si desidera eseguire l'elaborazione in background.

Si potrebbe passare il riferimento della vostra attività o la visualizzazione nel costruttore e l'uso che per passare i dati di nuovo nella vostra attività

class DownloadFilesTask extends AsyncTask<URL, Integer, List> { 
    private static final String TAG = null; 
    private MainActivity mActivity; 
    public DownloadFilesTask(MainActivity activity) { 
     mActivity = activity; 
     mActivity.setProgressBarIndeterminateVisibility(true); 
    } 

    protected List doInBackground(URL... url) { 
     List output = Downloader.downloadFile(url[0]); 
     return output; 
    } 

    protected void onProgressUpdate(Integer... progress) { 
     setProgressPercent(progress[0]); 
    } 

    private void setProgressPercent(final Integer integer) { 
     mActivity.setProgress(100*integer); 
    } 

    protected void onPostExecute(List output) { 

     mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output); 

     //you could do other processing here 
    } 
} 
+0

Suppongo che funzionerebbe se volessi per inviare più variabili dello stesso tipo, come un array di stringhe. Nel mio caso ho bisogno di passare un oggetto personalizzato insieme a una HashMap di parametri ... Ho la sensazione che dovrei usare qualcosa di diverso da AsyncTask ... –

+0

Puoi anche inviare un array di CustomObjects –

0

In alternativa, si potrebbe utilizzare un gestore di filo e USEA regolare per inviare i dati torna al thread dell'interfaccia utente ignorando la funzione handlemessage.

4

Riconosco che questa è una risposta tardiva, ma ecco quello che ho fatto per l'ultima volta.

Quando sto bisogno di passare un po 'di dati a un AsyncTask, posso creare sia mia classe, passare che in e quindi accedere le sue proprietà, in questo modo:

public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> { 

    @Override 
    protected Boolean doInBackground(MyClass... params) { 

     // Do blah blah with param1 and param2 
     MyClass myClass = params[0]; 

     String param1 = myClass.getParam1(); 
     String param2 = myClass.getParam2(); 

     return null; 
    } 
} 

e quindi l'accesso in questo modo:

AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass()); 

o posso aggiungere un costruttore per la mia classe AsyncTask, in questo modo:

public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> { 

    private String param1; 
    private String param2; 

    public MyAsyncTask(String param1, String param2) { 
     this.param1 = param1; 
     this.param2 = param2; 
    } 

    @Override 
    protected Boolean doInBackground(Void... params) { 

     // Do blah blah with param1 and param2 

     return null; 
    } 
} 

e quindi accedervi in ​​questo modo:

AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute(); 

Spero che questo aiuti!

0

Passando una semplice stringa:

public static void someMethod{ 
    String [] variableString= {"hello"}; 
    new MyTask().execute(variableString); 
} 

static class MyTask extends AsyncTask<String, Integer, String> { 

     // This is run in a background thread 
     @Override 
     protected String doInBackground(String... params) { 
      // get the string from params, which is an array 
      final String variableString = params[0]; 

      Log.e("BACKGROUND", "authtoken: " + variableString); 

      return null; 
     } 
    } 
Problemi correlati