La respuesta de Phoenixblade9 es correcta, pero para completarla, agregaría una cosa.
Hay un gran reemplazo para AsyncTask - AsyncTaskLoader, o los cargadores en general. Gestiona su ciclo de vida de acuerdo con el contexto desde el que se lo ha llamado (Actividad, Fragmento) e implementa un grupo de oyentes para ayudarlo a separar la lógica de un segundo hilo del hilo de la interfaz de usuario. Y generalmente es inmune al contexto de filtración.
Y no moleste el nombre; también es bueno para guardar datos.
Según lo prometido, publicaré mi código para AsyncTaskLoader withg varios objetos devueltos. El cargador es algo como esto:
public class ItemsLoader extends AsyncTaskLoader<HashMap<String, Object>>{
HashMap<String, Object> returned;
ArrayList<SomeItem> items;
Context cxt;
public EventsLoader(Context context) {
super(context);
//here you can initialize your vars and get your context if you need it inside
}
@Override
public HashMap<String, Object> loadInBackground() {
returned = getYourData();
return returned;
}
@Override
public void deliverResult(HashMap<String, Object> returned) {
if (isReset()) {
return;
}
this.returned = returned;
super.deliverResult(returned);
}
@Override
protected void onStartLoading() {
if (returned != null) {
deliverResult(returned);
}
if (takeContentChanged() || returned == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
onStopLoading();
returned = null;
}
En la función getYourData()
consigo tanto el código de mensaje de servidor o algún otro código de error y una ArrayList<SomeItem>
. Puedo usarlos en mi Fragmento de esta manera:
public class ItemListFragment extends ListFragment implements LoaderCallbacks<HashMap<String, Object>>{
private LoaderManager lm;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lm = getLoaderManager();
Bundle args = new Bundle();
args.putInt("someId", someId);
lm.initLoader(0, args, this);
}
@Override
public Loader<HashMap<String, Object>> onCreateLoader(int arg0, Bundle args) {
ItemsLoader loader = new ItemsLoader(getActivity(), args.getInt("someId"));
return loader;
}
@Override
public void onLoadFinished(Loader<HashMap<String, Object>> loader, HashMap<String, Object> data) {
if(data!=null){ if(data.containsKey("items")){
ArrayList<SomeItem> items = (ArrayList<EventItem>)data.get("items");
} else { //error
int error = 0;
if(data.containsKey("error")){
error = (Integer) data.get("error");
}
}
}
@Override
public void onLoaderReset(Loader<HashMap<String, Object>> arg0) {
}
El riesgo es en este caso si conservas la referencia a la asynctask cuando el Fragmento está muerto. El usuario podría decir hacer una acción que muestre el fragmento de la pila. En este caso, normalmente no querrás que el estado del Fragmento exista más. Si querías el estado de la asynctask porque contenía datos adicionales que querías usar, entonces mantendría la referencia al Fragmento aunque el Fragmento ya no exista. Creo que se separará de la actividad ya que pasó por el ciclo de vida normal, pero aún "existiría". – DeeV
@DeeV: Sí, eso es exactamente lo que me preocupaba – Matthias
¿Podría simplemente salirse con la asignación a una WeakReference y cancelar AsyncTask si el Fragmento se vuelve nulo? – DeeV