¿Cómo CursorLoader actualiza automáticamente la vista incluso si la aplicación está inactiva?

He estado trabajando en una pequeña aplicación de lista de tareas pendientes. Utilicé CursorLoader para actualizar ToDolistview de un proveedor de contenido. Tengo escrito una función onNewItemAdded() , que se llama cuando el usuario introduce un nuevo elemento en la vista de texto y hace clic en entrar. Consulte a continuación:

 public void onNewItemAdded(String newItem) { ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); values.put(ToDoContentProvider.KEY_TASK, newItem); cr.insert(ToDoContentProvider.CONTENT_URI, values); // getLoaderManager().restartLoader(0, null, this); // commented for the sake of testing } @Override protected void onResume() { super.onResume(); //getLoaderManager().restartLoader(0, null, this); // commented for the sake of testing } public Loader<Cursor> onCreateLoader(int id, Bundle args) { CursorLoader loader = new CursorLoader(this, ToDoContentProvider.CONTENT_URI, null, null, null, null); Log.e("GOPAL", "In the onCreateLoader"); return loader; } public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { int keyTaskIndex = cursor.getColumnIndexOrThrow(ToDoContentProvider.KEY_TASK); Log.e("GOPAL", "In the onLoadFinished"); todoItems.clear(); if (cursor.moveToNext() == false) Log.e("GOPAL", "Empty Cursor"); else { while (cursor.moveToNext()) { ToDoItem newItem = new ToDoItem(cursor.getString(keyTaskIndex)); todoItems.add(newItem); } aa.notifyDataSetChanged(); // aa is arrayadapter used for the listview } } 

He leído, CursorLoader actualiza automáticamente la vista, siempre que haya un cambio de datos en el proveedor de contenido db. Eso significa que supongo, getLoaderManager().restartLoader(0, null, this) tiene que ser llamado implícitamente cuando hay un cambio en los datos, ¿verdad? Pero eso no está sucediendo. Cada vez que agrego un nuevo elemento (el elemento se agrega al db de onNewItemAdded , pero restartLoader no se llama explícitamente), detenga esta actividad y retome la acción. No veo ninguna llamada implícita a restartLoader (aunque se cambia db) y el listview también no se actualiza con el nuevo elemento agregado. ¿Porqué es eso? ¿Cómo un CursorLoader actualiza automáticamente la vista incluso si la aplicación no está activa ??? Gracias 🙂

EDIT: También he utilizado getContext().getContentResolver().notifyChange(insertedId, null) en el inserto de mi proveedor de contenido.

Encontré la respuesta para mi pregunta. En general, CursorLoader no detecta automáticamente los cambios de datos y los carga para verlos. Necesitamos rastrear URI para los cambios. Esto se puede hacer siguiendo los siguientes pasos:

  1. Registro de un Observador en la resolución de contenido mediante el cursor usando: (Hecho en el método de consulta de ContentProvider)
    cursor.setNotificationUri(getContext().getContentResolver(), uri);

  2. Ahora, cuando hay algún cambio en los datos subyacentes de URI usando insert() / delete() / update(), notificamos al contentresolver sobre el cambio usando:

    getContext().getContentResolver().notifyChange(insertedId, null);

  3. Esto es recibido por el observador, nos registramos en el paso 1 y esto llama a ContentResolver.query() , que inturn llama a los proveedores Contentent query() método para devolver un cursor nuevo a loaderManager. LoaderManager llama a onLoadFinished pasando este cursor, junto con el Cursorloader donde actualizamos la Vista (usando adapter.swapcursor() ) con datos nuevos.

Para Custom AsyncTaskLoaders:

A veces necesitamos nuestro cargador personalizado en lugar de CursorLoader. Aquí podemos usar otro objeto other than cursor para apuntar a los datos cargados (como lista etc). En esto no tendremos previlige notificar a ContentResolver a través del cursor. La aplicación también puede no tener un proveedor de contenido, para realizar un seguimiento de los cambios de URI. En este escenario utilizamos BroadcastReceiver o ContentObserver explícito para lograr la actualización automática de la vista. Esto es como sigue:

  1. Tenemos que definir nuestro cargador personalizado que extiende AsyncTaskLoader e implementa todos sus métodos abstractos. A diferencia de CursorLoader , nuestro Custom Loader puede o no usar un proveedor de contenido y su constructor no puede llamar a ContentResolver.query() cuando este cargador se instala. Así que utilizamos un receptor de radiodifusión para servir el propósito.
  2. Necesitamos instanciar un BroadCastReceiver o ContentObserver en el método OnStartLoading() de la clase abstracta AsyncTaskLoader .
  3. Este receptor BroadCast debe ser definido para recibir transmisiones que cambian de datos desde el proveedor de contenido o cualquier evento del sistema (como la nueva aplicación instalada) y debe llamar al método onContentChanged() del cargador para notificar al cargador sobre el cambio de datos. Loader hace automáticamente el resto para cargar los datos actualizados y llama a onLoadFinished() para actualizar la vista.

Para más detalles, consulte esto: http://developer.android.com/reference/android/content/AsyncTaskLoader.html

Encontré esto muy útil para una explicación clara: http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html

Bueno, creo que puedes reiniciar el cargador en ciertos eventos. Por ejemplo, en mi caso tengo una actividad de TODO. Al hacer clic en 'añadir' opción, se lanza nueva actividad que tiene vista para alimentar nuevo TODO.

Estoy usando el siguiente código en la actividad de los padres onActivityResult ()

 getLoaderManager().restartLoader(0, null, this); 

Funciona bien para mí. Por favor comparta si hay algún enfoque mejor.

Gracias
Iuq

Obtener una referencia a su cargador al inicializar de la siguiente manera

  Loader dayWeatherLoader = getLoaderManager().initLoader(LOADER_DAY_WEATHER, null, this); 

A continuación, cree una clase que expanda ContentObserver como sigue

  class DataObserver extends ContentObserver { public DataObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { dayWeatherLoader.forceLoad(); } } 

A continuación, registre el observador de contenido en el método de ciclo de vida onResume como sigue

 @Override public void onResume() { super.onResume(); getContext().getContentResolver().registerContentObserver(CONTENTPROVIDERURI,true,new DayWeatherDataObserver(new Handler())); } 

Siempre que hay un cambio en los datos subyacentes del proveedor de contenido, se llamará el método onChange de contentobserver donde se puede pedir al cargador que vuelva a cargar los datos

  • LoaderManager con múltiples cargadores: cómo obtener el cursor correcto
  • Utilizar un Cursor devuelto desde un LoaderManager en un AsyncTask
  • Cargadores en Android Honeycomb
  • Paquete de Compatibilidad con Android y getLoaderManager ()
  • Dile a Android AsyncTaskLoader que recupere más datos
  • ¿Cuál es el propósito de startManagingCursor?
  • Android: CursorLoader, LoaderManager, SQLite
  • LoaderManager.restartLoader () siempre resultará en una llamada a onCreateLoader ()?
  • ¿Cuál es el alcance de LoaderManager?
  • Loader no se inicia después de llamar a initLoader ()?
  • AsyncTaskLoader vs AsyncTask
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.