2012-04-16 12 views
5

He convertido mi AsyncTask en un AsyncTaskLoader (principalmente para hacer frente a los cambios de configuración). Tengo un TextView que estoy usando como estado de progreso y estaba usando onProgressUpdate en el AsyncTask para actualizarlo. No se ve como AsyncTaskLoader tiene un equivalente, por lo que durante loadInBackground (en el AsyncTaskLoader) estoy usando esto:Actualizar la interfaz de usuario de un AsyncTaskLoader

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

estoy usando esto en un Fragment, razón por la que estoy usando getActivity(). Esto funciona bastante bien, excepto cuando ocurre un cambio de configuración, como cambiar la orientación de la pantalla. Mi AsyncTaskLoader sigue en ejecución (por lo que estoy usando un AsyncTaskLoader), pero el runOnUiThread parece omitirse.

No estoy seguro de por qué se salta o si esta es la mejor manera de actualizar la interfaz de usuario de AsyncTaskLoader.

ACTUALIZACIÓN:

acabé volviendo de nuevo a un AsyncTask ya que parece más adecuado para las actualizaciones de la interfaz de usuario. Desearía poder fusionar lo que funciona con un AsyncTask con un AsyncTaskLoader.

Respuesta

4

En realidad es posible. Básicamente, debe subclasificar el AsyncTaskloader e implementar un método publishMessage(), que utilizará un Handler para entregar el mensaje de progreso a cualquier clase que implemente la interfaz ProgressListener (o como quiera llamar).

Descarga esta para un ejemplo: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html (mensaje si se queda sin conexión) - esto se basó de http://habrahabr.ru/post/131560/

+0

Creo que este es un truco muy inteligente. Nunca pensé en ello. Estaba buscando la manera de enviar mis actualizaciones de progreso usando cargadores. Voy a intentarlo y dejarte saber. ¡Creo que tu solución debería funcionar! – douggynix

+0

El enlace parece haber ido mal. [Aquí] (https://yadi.sk/d/qovznXrpUbbum) está funcionando (creo que es lo mismo). – EmmanuelMess

0

En la clase en la que implementa LoaderManager.LoaderCallback (probablemente su Actividad), hay un método onLoadFinished() que debe sobrescribir. Esto es lo que se devuelve cuando el AsyncTaskLoader ha terminado de cargarse.

+1

Puedo estar equivocado pero no se llama 'onLoadFinished' cuando' AsyncTaskLoader' se termina de cargar? No estoy exactamente seguro de cómo aborda mi problema, pero soy nuevo en 'AsyncTaskLoaders', por lo que me puede estar perdiendo algo. ¿'OnLoadFinished' es equivalente a' onProgressUpdate' en 'AsyncTask'? –

+0

Es el equivalente de 'onPostExecute' –

+2

Eso no es lo que estoy buscando. Necesito el equivalente de 'onProgressUpdate', por lo que puedo mostrar un estado mientras se ejecuta el proceso en segundo plano. No creo que 'AsyncTaskLoader' tenga uno. –

1

Respondiendo a mi propia pregunta, pero por lo que puedo decir, AsyncTaskLoader no es el mejor para usar si necesita actualizar la interfaz de usuario.

4

Emm ... no debería estar haciendo esto.

porque cómo una clase anónima accede al método o campo de clase primaria almacenando una referencia invisible a la clase principal.

por ejemplo, que tienen 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. 
    } 
} 

el compilador en realidad va a generar algo como esto:

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

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

Así, cuando sus padres Activity destruye (debido al cambio de configuración, por ejemplo) , y su clase anónima aún existe, toda la actividad no puede ser editada. (porque alguien todavía tiene una referencia).

QUE SE CONVIERTE EN UNA FUGA DE MEMORIA Y HAGA QUE SU APLICACIÓN SEA LIMBO !!!

Si fuera yo, me pondría en práctica el "onProgressUpdate()" para los cargadores de este tipo:

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)); 
    } 
} 

Y en su clase 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(); 
    } 
} 

recordar a deleteObserver() durante onDestroy() es importante , de esta manera, el cargador no mantiene una referencia a su actividad para siempre. (el cargador probablemente se mantendrá vivo durante su ciclo de vida Application ...)

+1

Parece que te falta un setChanged() en el Observable, ¿verdad? – Maxr1998

Cuestiones relacionadas