2012-04-16 8 views
5

Ho convertito il mio AsyncTask in un AsyncTaskLoader (principalmente per gestire le modifiche alla configurazione). Ho un TextView che sto usando come stato di avanzamento e stava usando onProgressUpdate nel AsyncTask per aggiornarlo. Non sembrare AsyncTaskLoader ha un equivalente, quindi durante loadInBackground (nel AsyncTaskLoader) Sto usando questo:UI aggiornamento da AsyncTaskLoader

getActivity().runOnUiThread(new Runnable() { 
    public void run() { 
     ((TextView)getActivity().findViewById(R.id.status)).setText("Updating..."); 
    } 
}); 

Sto usando questo in un Fragment, ed è per questo che sto usando getActivity(). Funziona piuttosto bene, tranne quando avviene una modifica alla configurazione, come cambiare l'orientamento dello schermo. Il mio AsyncTaskLoader continua a funzionare (motivo per cui sto utilizzando un AsyncTaskLoader), ma il runOnUiThread sembra essere saltato.

Non so perché viene saltato o se questo è il modo migliore per aggiornare l'interfaccia utente da un AsyncTaskLoader.

UPDATE:

ho finito per ritornare alla una AsyncTask come sembra più adatto per gli aggiornamenti dell'interfaccia utente. Vorrei poter unire ciò che funziona con uno AsyncTask con uno AsyncTaskLoader.

risposta

4

In realtà è possibile. In sostanza, è necessario creare una sottoclasse dello AsyncTaskloader e implementare un metodo publishMessage(), che utilizzerà un Handler per recapitare il messaggio di stato a qualsiasi classe che implementa l'interfaccia ProgressListener (o qualsiasi altra cosa si voglia chiamare).

Scarica questo per un esempio: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html (messaggio me se va offline) - questo è stato basato su http://habrahabr.ru/post/131560/

+0

Penso che questo sia un trucco molto intelligente. Non ci avevo mai pensato. Stavo cercando il modo di inviare i miei aggiornamenti di avanzamento tramite Loaders. Ci proverò e ti farò sapere. Penso che la tua soluzione dovrebbe funzionare !! – douggynix

+0

Il collegamento sembra essere andato male. [Qui] (https://yadi.sk/d/qovznXrpUbbum) è funzionante (penso sia lo stesso). – EmmanuelMess

0

Nella classe in cui si implementa LoaderManager.LoaderCallback (presumibilmente l'attività), esiste un metodo onLoadFinished() che è necessario sovrascrivere. Questo è ciò che viene restituito quando lo AsyncTaskLoader ha terminato il caricamento.

+1

Posso sbagliarmi ma non è "onLoadFinished" chiamato quando il caricamento di "AsyncTaskLoader' è terminato? Non sono proprio sicuro di come questo risolva il mio problema, ma sono nuovo di 'AsyncTaskLoaders', quindi potrei mancare qualcosa. 'OnLoadFinished' è l'equivalente di' onProgressUpdate' in un 'AsyncTask'? –

+0

È l'equivalente di 'onPostExecute' –

+2

Non è quello che sto cercando. Ho bisogno dell'equivalente di 'onProgressUpdate', quindi posso mostrare uno stato mentre il processo in background è in esecuzione. Non penso che 'AsyncTaskLoader' ne abbia uno. –

1

Rispondere alla mia domanda, ma da quello che posso dire, AsyncTaskLoader non è il migliore da utilizzare se è necessario aggiornare l'interfaccia utente.

4

Emm ... non dovrebbe fare questo.

perché il modo in cui una classe anonima accede al metodo o al campo della classe padre memorizzando un riferimento invisibile alla classe genitore.

per esempio, si ha un Activity:

public class MyActivity 
    extends Activity 
{ 
    public void someFunction() { /* do some work over here */ } 

    public void someOtherFunction() { 
     Runnable r = new Runnable() { 
      @Override 
      public void run() { 
       while (true) 
        someFunction(); 
      } 
     }; 
     new Thread(r).start(); // use it, for example here just make a thread to run it. 
    } 
} 

il compilatore in realtà generare qualcosa di simile:

private static class AnonymousRunnable { 
    private MyActivity parent; 
    public AnonymousRunnable(MyActivity parent) { 
     this.parent = parent; 
    } 

    @Override 
    public void run() { 
     while (true) 
      parent.someFunction(); 
    } 
} 

Così, quando i vostri genitori Activity distrugge (a causa di modifica della configurazione, ad esempio) e la tua classe anonima esiste ancora, l'intera attività non può essere gc-ed. (perché qualcuno ha ancora un riferimento.)

CHE DIVENTA UNA PERDITA DI MEMORIA E FAI LA TUA APP GO LIMBO !!!

Se me è stato, vorrei attuare il "onProgressUpdate()" per i caricatori in questo modo:

public class MyLoader extends AsyncTaskLoader<Something> { 
    private Observable mObservable = new Observable(); 
    synchronized void addObserver(Observer observer) { 
     mObservable.addObserver(observer); 
    } 
    synchronized void deleteObserver(Observer observer) { 
     mObservable.deleteObserver(observer); 
    } 

    @Override 
    public void loadInBackground(CancellationSignal signal) 
    { 
     for (int i = 0;i < 100;++i) 
      mObservable.notifyObservers(new Integer(i)); 
    } 
} 

E nella classe Activity

public class MyActivity extends Activity { 
    private Observer mObserver = new Observer() { 
     @Override 
     public void update(Observable observable, Object data) { 
      final Integer progress = (Integer) data; 
      mTextView.post(new Runnable() { 
       mTextView.setText(data.toString()); // update your progress.... 
      }); 
     } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreated(savedInstanceState); 

     MyLoader loader = (MyLoader) getLoaderManager().initLoader(0, null, this); 
     loader.addObserver(mObserver); 
    } 

    @Override 
    public void onDestroy() { 
     MyLoader loader = (MyLoader) getLoaderManager().getLoader(0); 
     if (loader != null) 
      loader.deleteObserver(mObserver); 
     super.onDestroy(); 
    } 
} 

ricordarsi di deleteObserver() durante onDestroy() è importante in questo modo il caricatore non tiene per sempre un riferimento alla tua attività. (il caricatore sarà probabilmente tenuto in vita durante il ciclo di vita Application ...)

+1

Sembra che manchi un setChanged() sull'osservabile, vero? – Maxr1998