android - oncreateloader - loadermanager
AsyncTaskLoader no se ejecuta (7)
Creo que la mejor solución para el paquete de compatibilidad es anular el método AsyncTaskLoader.onStartLoading .
p.ej
@Override
protected void onStartLoading() {
if(dataIsReady) {
deliverResult(data);
} else {
forceLoad();
}
}
Quiero implementar AsyncTaskLoader en mi proyecto utilizando el Paquete de compatibilidad, así que seguí el manual del cargador en los documentos de Android.
El problema es que el cargador no hace nada, parece que loadInBackground()
nunca se llama
¿Alguna idea de lo que está mal en mi código? ( ExpandableListFragment
extiende Fragment
, pero no anula ningún método crítico)
Gracias :-)
/**EDITAR:
Me di cuenta (tarde, soy un imbécil) que AsyncTaskLoader es una clase abstracta, así que necesito crear una subclase ... m (__) m Dejo la pregunta en caso de que alguien venga detrás de mí, quién sabe ...
public class AgendaListFragment extends ExpandableListFragment implements
LoaderManager.LoaderCallbacks<JSONArray> {
private TreeMap<Integer, ArrayList<Evento>> mItems = new TreeMap<Integer, ArrayList<Evento>>();
private AgendaListAdapter mAdapter;
private ProgressBar mProgressBar;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_agenda, container);
mProgressBar = (ProgressBar) root.findViewById(R.id.loading);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new AgendaListAdapter(getActivity());
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<JSONArray> onCreateLoader(int arg0, Bundle arg1) {
mProgressBar.setVisibility(View.VISIBLE);
return new AsyncTaskLoader<JSONArray>(getActivity()) {
@Override
public JSONArray loadInBackground() {
return getDataFromService(AgendaServices.LISTADO_MES);
}
};
}
@Override
public void onLoadFinished(Loader<JSONArray> loader, JSONArray data) {
// Some stuff to turn JSONArray into TreeMap
mProgressBar.setVisibility(View.GONE);
mAdapter.setItems(mItems);
}
@Override
public void onLoaderReset(Loader<JSONArray> arg0) {
mAdapter.setItems(null);
mProgressBar.setVisibility(View.VISIBLE);
}
}
En cuanto a la discusión en https://code.google.com/p/android/issues/detail?id=14944 , la verificación de takeContentChanged
parece ser un paso importante.
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
Esto es exactamente una solución, pero debería funcionar. Estoy bastante seguro de que la biblioteca de compatibilidad está rota. Prueba esto:
getLoaderManager().initLoader(0, null, this).forceLoad();
He tenido el mismo problema después de migrar de CursorLoader a AsyncTaskLoader.
la documentación dice : Las subclases del Loader<D>
generalmente deben implementar al menos onStartLoading (), onStopLoading (), onForceLoad () y onReset () .
AsyncTaskLoader extiende Loader pero no implementa onStartLoading (), onStopLoading (), onReset () . ¡Debe implementarlo usted mismo!
@ davidshen84 propuso una buena solución. Solo agregué la comprobación de takeContentChanged.
@Override
protected void onStartLoading() {
try {
if (data != null) {
deliverResult(data);
}
if (takeContentChanged() || data == null) {
forceLoad();
}
Log.d(TAG, "onStartLoading() ");
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
Usar forceLoad () está bien (no es una mala práctica). Vea lo que says documentación:
En general, solo debe llamar a esto cuando se inicia el cargador, es decir, isStarted () devuelve verdadero.
Todavía tenía el problema de que no se llamaba a la carga de datos. Finalmente eliminé AsyncTaskLoader (la versión de la biblioteca de soporte) y usé solo AsyncTask (no desde la biblioteca de soporte) para hacer el trabajo. Y funcionó.
Podría ser suficiente para tus necesidades también.
Descripción y ejemplo: http://developer.android.com/reference/android/os/AsyncTask.html .
Tienes que extender la clase AsyncTask .
El método doInBackground hará el trabajo y en el método onPostExecute obtendrá el resultado. Para iniciar AsyncTask , invocará el método execute en su instancia. Vea el enlace.
Tomé el código fuente de CursorLoader
de android framework y escribí una clase CustomTaskLoader<T>
para facilitar el trabajo.
básicamente implementa estas dos funciones:
public abstract T runTaskInBackground(CancellationSignal signal);
public abstract void cleanUp(T oldResult);
vea el uso en las actividades y los fragmentos, por ejemplo este: (bueno, mi código simplemente ignora el signo de CancellationSignal
, es un TODO
en mi lista, pero es libre de usarlo).
return new CustomTaskLoader<Cursor>(getActivity().getApplicationContext())
{
@Override
public Cursor runTaskInBackground(CancellationSignal signal)
{
return SiteSession.getAllPostsCursor(PostListAdapter.POST_COLUMNS);
}
@Override
public void cleanUp(Cursor oldCursor)
{
if (!oldCursor.isClosed())
oldCursor.close();
}
}
Cheok Yan Cheng tiene toda la razón:
La comprobación de takeContentChanged también parece un paso importante.
Si escribe su método de esta manera:
protected void onStartLoading() {
forceLoad();
}
notará que cuando se onStartLoading
una actividad secundaria y luego regresa a la principal, se onStartLoading
nuevamente la llamada a la onStartLoading
(y, por loadInBackground
tanto, a loadInBackground
).
¿Qué puedes hacer? Establezca una variable interna ( mContentChanged
) en verdadero dentro del constructor; a continuación, compruebe esta variable dentro de onStartLoading
. Solo cuando sea verdad, empieza a cargar de verdad:
package example.util;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
public abstract class ATLoader<D> extends AsyncTaskLoader<D> {
public ATLoader(Context context) {
super(context);
// run only once
onContentChanged();
}
@Override
protected void onStartLoading() {
// That''s how we start every AsyncTaskLoader...
// - code snippet from android.content.CursorLoader (method onStartLoading)
if (takeContentChanged()) {
forceLoad();
}
}
}