android - para - Actualizar la interfaz de usuario de AsyncTaskLoader
instalar android en pc (4)
He convertido mi AsyncTask
a 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 AsyncTask
para actualizarlo. No parece que AsyncTaskLoader
tenga un equivalente, así que durante loadInBackground
(en AsyncTaskLoader
) estoy usando esto:
getActivity().runOnUiThread(new Runnable() {
public void run() {
((TextView)getActivity().findViewById(R.id.status)).setText("Updating...");
}
});
Estoy usando esto en un Fragment
, por eso 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 runOnUiThread
parece runOnUiThread
.
No estoy seguro de por qué se omite o si esta es la mejor manera de actualizar la UI desde un AsyncTaskLoader
.
ACTUALIZAR:
Terminé volviendo a un AsyncTask
ya que parece más adecuado para las actualizaciones de la interfaz de usuario. Desearía poder combinar lo que funciona con AsyncTask
con AsyncTaskLoader
.
En la clase en la que implementa LoaderManager.LoaderCallback
(presumiblemente su actividad), hay un método onLoadFinished()
que debe sobrescribir. Esto es lo que se devuelve cuando el AsyncTaskLoader
ha terminado de cargarse.
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.
En realidad es posible. Esencialmente necesita subclasificar el AsyncTaskloader
e implementar un método publishMessage()
, que usará un Handler
para entregar el mensaje de progreso a cualquier clase que implemente la interfaz ProgressListener
(o como quiera llamarlo).
Descargue esto para obtener un ejemplo: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html (envíeme un mensaje si se desconecta) - esto se basó en http://habrahabr.ru/post/131560/
Emm ... no deberías estar haciendo esto.
porque cómo es que una clase anónima accede al método o campo de la clase padre almacenando una referencia invisible a la clase padre.
por ejemplo, tienes una 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 realmente 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();
}
}
Por lo tanto, cuando la Activity
primaria se destruye (debido a cambios en la configuración, por ejemplo) y su clase anónima aún existe, toda la actividad no puede ser modificada. (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, implementaría el "onProgressUpdate ()" para cargadores como este:
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 tu clase de 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();
}
}
recuerde que deleteObserver()
durante onDestroy()
es importante, de esta forma el cargador no mantiene una referencia a su actividad para siempre. (el cargador probablemente se mantendrá vivo durante su ciclo de vida de la Application
...)