Skip to content

Most visited

Recently visited

navigation

Cargadores

Introducidos en Android 3.0, los cargadores simplifican la carga asincrónica de datos en una actividad o un fragmento. Los cargadores tienen estas características:

Resumen de la loader API

Muchas clases e interfaces pueden participar en el uso de cargadores en una aplicación. Se las resume en esta tabla:

Clase/interfaz Descripción
LoaderManager Clase abstracta asociada con una Activity o unFragment para administrar una o más instancias de Loader. Esto ayuda a una aplicación a administrar operaciones más prolongadas junto con el ciclo de vida de la Activity o el Fragment. El uso más común de esto es con un CursorLoader; sin embargo, las aplicaciones pueden escribir sus propios cargadores para cargar otros tipos de datos.

Solo hay un LoaderManager por actividad o fragmento. Sin embargo, un LoaderManager puede tener varios cargadores.
LoaderManager.LoaderCallbacks Interfaz de callback para que un cliente interactúe con el LoaderManager. Por ejemplo, se usa el método de callback onCreateLoader() para crear un cargador nuevo.
Loader Clase abstracta que realiza una carga asincrónica de datos. Esta es la clase base para un cargador. En general usarás CursorLoader, pero puedes implementar tu propia subclase. Mientras están activos, los cargadores deben controlar el origen de los datos y entregar resultados nuevos cuando el contenido cambia.
AsyncTaskLoader Cargador abstracto que proporciona una AsyncTask para hacer la tarea.
CursorLoader Subclase de AsyncTaskLoader que consulta el ContentResolver y devuelve un Cursor. Esta clase implementa el protocolo de Loader de manera estandarizada para consultar cursores y se basa en AsyncTaskLoader para realizar la consulta de cursores en segundo plano, a fin de no bloquear la IU de la aplicación. Usar este cargador es la mejor manera de cargar datos asincrónicamente de un ContentProvider, en lugar de realizar una consulta administrada mediante las API del fragmento o de la actividad.

Las clases y las interfaces de la tabla precedente son los componentes esenciales que usarás para implementar un cargador en la aplicación. No los necesitarás a todos para cada cargador que crees, pero siempre necesitarás una referencia al LoaderManager para iniciar un cargador y una implementación de una clase Loader como CursorLoader. Las siguientes secciones muestran cómo usar estas clases e interfaces en una aplicación.

Uso de cargadores en una aplicación

Esta sección describe cómo usar cargadores en una aplicación con Android. Una aplicación que usa cargadores usualmente incluye lo siguiente:

Inicio de un cargador

El LoaderManager administra una o más instancias de Loader en una Activity o unFragment. Solo hay un LoaderManager por actividad o fragmento.

Generalmente, un Loader se inicia en el método onCreate() de la actividad o dentro del método onActivityCreated() del fragmento. Para ello, debes seguir estos pasos:

// Prepare the loader.  Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);

El método initLoader() adopta los siguientes parámetros:

La llamada initLoader() garantiza que un cargador sea iniciado y esté activo. Tiene dos resultados posibles:

En ambos casos, la implementación de LoaderManager.LoaderCallbacks está asociada con el cargador y se la llamará cuando el estado del cargador cambie. Si cuando se realiza esta llamada el emisor está en estado de inicio, y el cargador solicitado ya existe y ha generado sus datos , el sistema llama a onLoadFinished() inmediatamente (durante initLoader()). Por ello, debes estar preparado para que esto suceda. Para obtener más información sobre este callback, consulta onLoadFinished.

Ten en cuenta que el método initLoader() devuelve el Loader que se crea, pero no necesitas capturar una referencia para él. El LoaderManager administra la vida del cargador automáticamente. El LoaderManager inicia y detiene la carga cuando es necesario, y mantiene el estado del cargador y el contenido asociado. Esto implica que en pocas ocasiones interactúas con los cargadores directamente (no obstante, si deseas ver un ejemplo del uso de métodos de cargador para perfeccionar el comportamiento de un cargador, consulta el ejemplo LoaderThrottle). Se usan con más frecuencia los métodos LoaderManager.LoaderCallbacks para intervenir en el proceso de carga cuando se produce un evento particular. Para obtener más información sobre este tema, consulta Uso de los callbacks del LoaderManager.

Reinicio de un cargador

Cuando se usa initLoader(), como se muestra arriba, este usa un cargador existente con el ID especificado si hay uno. De lo contrario, lo crea. Pero, a veces, se desea descartar datos viejos y comenzar de nuevo.

Para descartar datos antiguos, se usa restartLoader(). Por ejemplo, esta implementación de SearchView.OnQueryTextListener reinicia el cargador cuando la consulta del usuario cambia. El cargador se debe reiniciar para que pueda usar el filtro de búsqueda revisado para realizar una consulta nueva.

public boolean onQueryTextChanged(String newText) {
    // Called when the action bar search text has changed.  Update
    // the search filter, and restart the loader to do a new query
    // with this filter.
    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    getLoaderManager().restartLoader(0, null, this);
    return true;
}

Uso de los callbacks del LoaderManager

LoaderManager.LoaderCallbacks es una interfaz de callback que permite que un cliente interactúe con el LoaderManager.

Se espera que los cargadores, especialmente el CursorLoader, retengan los datos después de que se los haya detenido. Esto permite que las aplicaciones mantengan los datos en los métodos onStop() y onStart() de la actividad o el fragmento para que, cuando los usuarios vuelvan a la aplicación, no tengan que esperar que los datos vuelvan a cargarse. Los métodos LoaderManager.LoaderCallbacks se utilizan para saber cuándo crear un cargador nuevo y para decir a la aplicación cuándo es el momento de detener el uso de los datos de un cargador.

LoaderManager.LoaderCallbacks incluye estos métodos:

Estos métodos se describen más detalladamente en las secciones siguientes.

onCreateLoader

Cuando intentas acceder a un cargador (por ejemplo, mediante initLoader()), este comprueba si el cargador especificado por el ID existe. Si no lo hace, activa el método LoaderManager.LoaderCallbacks onCreateLoader(). Aquí es donde creas un cargador nuevo. Generalmente, será CursorLoader, pero puedes implementar tu propia subclase de Loader.

En este ejemplo, el método de callback onCreateLoader() crea un CursorLoader. Debes crear el CursorLoader con tu método constructor, que requiere el conjunto completo de información necesario para realizar una consulta al ContentProvider. Específicamente, necesita lo siguiente:

Por ejemplo:

 // If non-null, this is the current filter the user has provided.
String mCurFilter;
...
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // This is called when a new Loader needs to be created.  This
    // sample only has one Loader, so we don't care about the ID.
    // First, pick the base URI to use depending on whether we are
    // currently filtering.
    Uri baseUri;
    if (mCurFilter != null) {
        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                  Uri.encode(mCurFilter));
    } else {
        baseUri = Contacts.CONTENT_URI;
    }

    // Now create and return a CursorLoader that will take care of
    // creating a Cursor for the data being displayed.
    String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
            + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
            + Contacts.DISPLAY_NAME + " != '' ))";
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}

onLoadFinished

Se llama a este método cuando un cargador previamente creado termina de cargarse. Este método se llama antes de la liberación de los últimos datos que se proporcionaron para este cargador. En este punto, debes quitar todo uso de los datos viejos (ya que se liberarán pronto), pero no debes hacer tu propia liberación de los datos, ya que el cargador es su propietario y se encargará de eso.

El cargador liberará los datos una vez que detecte que la aplicación ya no los usa. Por ejemplo, si los datos representan un cursor de un CursorLoader, no debes llamar a close() en él tú mismo. Si el cursor se dispone en un CursorAdapter, debes usar el método swapCursor() para que el Cursor anterior no se cierre. Por ejemplo:

// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter; ... public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in.  (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); }

onLoaderReset

Este método recibe una llamada durante el restablecimiento de un cargador previamente creado. Esto hace que los datos no estén disponibles. Este callback te permite saber cuándo se liberarán los datos para que puedas quitar la referencia a ellos.  

Esta implementación llama a swapCursor() con un valor null:

// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...

public void onLoaderReset(Loader<Cursor> loader) {
    // This is called when the last Cursor provided to onLoadFinished()
    // above is about to be closed.  We need to make sure we are no
    // longer using it.
    mAdapter.swapCursor(null);
}

Ejemplo

A modo de ejemplo, la siguiente es la implementación completa de un Fragment que muestra una ListView con los resultados de una consulta de los contactos del proveedor de contenido. Usa un CursorLoader para manejar la consulta sobre el proveedor.

Para que una aplicación acceda a los contactos de un usuario, como se muestra en este ejemplo, el manifiesto debe incluir el permiso READ_CONTACTS.

public static class CursorLoaderListFragment extends ListFragment
        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {

    // This is the Adapter being used to display the list's data.
    SimpleCursorAdapter mAdapter;

    // If non-null, this is the current filter the user has provided.
    String mCurFilter;

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

        // Give some text to display if there is no data.  In a real
        // application this would come from a resource.
        setEmptyText("No phone numbers");

        // We have a menu item to show in action bar.
        setHasOptionsMenu(true);

        // Create an empty adapter we will use to display the loaded data.
        mAdapter = new SimpleCursorAdapter(getActivity(),
                android.R.layout.simple_list_item_2, null,
                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
        setListAdapter(mAdapter);

        // Prepare the loader.  Either re-connect with an existing one,
        // or start a new one.
        getLoaderManager().initLoader(0, null, this);
    }

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Place an action bar item for searching.
        MenuItem item = menu.add("Search");
        item.setIcon(android.R.drawable.ic_menu_search);
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        SearchView sv = new SearchView(getActivity());
        sv.setOnQueryTextListener(this);
        item.setActionView(sv);
    }

    public boolean onQueryTextChange(String newText) {
        // Called when the action bar search text has changed.  Update
        // the search filter, and restart the loader to do a new query
        // with this filter.
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
        getLoaderManager().restartLoader(0, null, this);
        return true;
    }

    @Override public boolean onQueryTextSubmit(String query) {
        // Don't care about this.
        return true;
    }

    @Override public void onListItemClick(ListView l, View v, int position, long id) {
        // Insert desired behavior here.
        Log.i("FragmentComplexList", "Item clicked: " + id);
    }

    // These are the Contacts rows that we will retrieve.
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
        Contacts._ID,
        Contacts.DISPLAY_NAME,
        Contacts.CONTACT_STATUS,
        Contacts.CONTACT_PRESENCE,
        Contacts.PHOTO_ID,
        Contacts.LOOKUP_KEY,
    };
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created.  This
        // sample only has one Loader, so we don't care about the ID.
        // First, pick the base URI to use depending on whether we are
        // currently filtering.
        Uri baseUri;
        if (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                    Uri.encode(mCurFilter));
        } else {
            baseUri = Contacts.CONTENT_URI;
        }

        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        return new CursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION, select, null,
                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in.  (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed.  We need to make sure we are no
        // longer using it.
        mAdapter.swapCursor(null);
    }
}

Más ejemplos

Se proporcionan algunos ejemplos diferentes en ApiDemos que ilustran cómo usar los cargadores:

Para obtener información sobre la descarga y la instalación de ejemplos de SDK, consulta Obtención de los ejemplos.

This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.