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?
- ¿Cómo insertar correctamente valores en la base de datos SQLite utilizando el método insert () de ContentProvider mediante un CursorLoader?
- Cargadores en Android Honeycomb
- Algunas preguntas sobre los cursores de la base de datos SQLite en Android
- Android getContentResolver (). NotifyChange () no reinicia mi cargador
- LoaderManager con múltiples cargadores: cómo obtener el cursor correcto
- ¿Cuáles son los beneficios de CursorLoaders?
- Diferencia entre restartLoader y onContentChanged
- Filtro ListView con CursorLoader y CursorAdapter personalizado
- AsyncTaskLoader vs AsyncTask
- Android Loaders lifecycle, o: onStopLoading () siempre se llama antes de onReset ()?
- ¿Cómo CursorLoader actualiza automáticamente la vista incluso si la aplicación está inactiva?
- ¿Qué CursorAdapter tengo que usar?
- Error al utilizar CursorLoader para cargar datos de ContentProvider
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)
- -bash: android: comando no encontrado en Mac OSX
- ¿Cómo hacer referencia al atributo de color en drawable?