Android 3.0 – ¿Cuáles son las ventajas de usar instancias de LoaderManager exactamente?

Con 3.0 obtuvimos el LoaderManager fantasía, que maneja la carga de datos usando AsyncTaskLoader , CursorLoader y otras instancias personalizadas de Loader . Pero la lectura a través de los documentos para estos sólo no podía obtener el punto: ¿cómo son mejor que sólo el uso de la AsyncTask buen viejo para la carga de datos?

Bueno, son mucho más fáciles de implementar y cuidar de todo lo relacionado con la gestión del ciclo de vida, por lo que son mucho menos propensos a errores.

Basta con mirar el código de ejemplo, para mostrar el resultado de una consulta de cursor que permite al usuario filtrar interactivamente el conjunto de resultados a través de un campo de entrada de consulta en la barra de acción:

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

La correcta implementación de este ejemplo completo con AsyncTask va a implicar mucho más código … e incluso entonces, ¿vas a implementar algo tan completo y funcionando bien? Por ejemplo, ¿mantendrá su implementación el Cursor cargado en los cambios de configuración de la actividad, por lo que no es necesario volver a consultarlo cuando se crean las nuevas instancias? LoaderManager / Loader lo hará automáticamente para usted, además de cuidar de crear y cerrar correctamente el Cursor basado en el ciclo de vida de la actividad.

También tenga en cuenta que el uso de este código no requiere que usted piense en absoluto acerca de asegurarse de que el trabajo largo de ejecución se realiza fuera del hilo principal de la interfaz de usuario. LoaderManager y CursorLoader se encargarán de todo esto para usted, asegurándose de que nunca bloqueará el hilo principal mientras interactúa con el cursor. Para hacer esto correctamente, realmente necesita tener dos objetos Cursor activos al mismo tiempo en puntos, por lo que puede seguir mostrando una interfaz de usuario interactiva con su cursor actual mientras se está cargando el siguiente que se va a mostrar. LoaderManager hace todo eso por usted.

Esto es sólo una API mucho más sencilla – no hay necesidad de saber acerca de AsyncTask y pensar en lo que necesita ejecutarse en segundo plano, sin necesidad de pensar en el ciclo de vida de la actividad ni en cómo usar las viejas API de "cursor administrado" en Activity (que didn ' T funciona, así como LoaderManager de todos modos).

(Btw no se olvide de la nueva biblioteca estática de "soporte" que le permite utilizar la API completa de LoaderManager en versiones anteriores de Android hasta 1.6)

  • Android Fragment - Utilizar el gestor de carga de la actividad en lugar de Fragmento. ¿Está bien?
  • Referencia de LoaderManager no encontrada con API Nivel 17
  • Utilizar CursorLoader para consultar la base de datos SQLite y rellenar AutoCompleteTextView
  • ¿Cómo puedo actualizar el cursor desde un CursorLoader?
  • Utilizar un Cursor devuelto desde un LoaderManager en un AsyncTask
  • Poblar listview de ListAdapter o SimpleCursorAdapter
  • ¿Está bien tener una instancia de SQLiteOpenHelper compartida por todas las actividades en una aplicación de Android?
  • LoaderManager: cómo agarrar a mi variable / método de mis cargadores?
  • Matrixcursor con proveedor de contenido no-db
  • ¿Cuál es el alcance de LoaderManager?
  • ¿Por qué onLoadFinished se llama de nuevo después de que se reanude el fragmento?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.