ContentLoader no se actualiza correctamente después de cambios en la base de datos

Tengo un SQLiteDatabase cuyos datos son manejados por un proveedor de contenido. Estoy usando un diseño con pestañas. La primera pestaña tiene la capacidad de agregar filas a la base de datos, mientras que la segunda ficha muestra los elementos de la base de datos. Al agregar elementos a la base de datos desde la primera pestaña, los cambios deben reflejarse cuando me muevo a la otra pestaña.

Los datos se están agregando a la base de datos correctamente, ya la primera apertura de la aplicación, todos los datos actuales (y cualquier cosa nueva agregada en una versión anterior de la aplicación) aparecerá. Sin embargo, agregar nuevos elementos a la base de datos no se refleja en el ListFragment.

@Override public void onClick(View v) { if(v == addSale) { Item item = new Item(rn(), null, 100); data.add(item); total += item.getAmount(); } else if(v == save) { for(Item i: data) { ContentValues cv = new ContentValues(); cv.put(DatabaseProvider.COLUMN_COST, i.getAmount()); cv.put(DatabaseProvider.COLUMN_ITEM, i.getItem()); cv.put(DatabaseProvider.COLUMN_PERSON, i.getPerson()); this.getActivity().getContentResolver().insert(DatabaseProvider.CONTENT_URI, cv); } total = 0; data.clear(); } else if(v == clear) { data.clear(); total = 0; } items.notifyDataSetChanged(); totalView.setText(Item.format(total)); } 

Aquí es donde añado los artículos a la base de datos específicamente con estas líneas:

 ContentValues cv = new ContentValues(); cv.put(DatabaseProvider.COLUMN_COST, i.getAmount()); cv.put(DatabaseProvider.COLUMN_ITEM, i.getItem()); cv.put(DatabaseProvider.COLUMN_PERSON, i.getPerson()); this.getActivity().getContentResolver().insert(DatabaseProvider.CONTENT_URI, cv); 

Como dije antes, los elementos se ponen en la base de datos correctamente, por lo que estoy razonablemente seguro de que esto es correcto.

Aquí está el método insert de mi DatabaseProvider

 @Override public Uri insert(Uri uri, ContentValues initialValues) { if (sUriMatcher.match(uri) != TABLE) { throw new IllegalArgumentException("Invalid URI: " + uri); } if (initialValues == null) { initialValues = new ContentValues(); } SQLiteDatabase db = dbHelper.getWritableDatabase(); long rowId = db.insert(TABLE_SALES, COLUMN_COST, initialValues); if (rowId > 0) { Uri newUri = ContentUris.withAppendedId(CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(uri, null); return newUri; } throw new SQLException("Failed to insert row into: " + uri); } 

De los diversos tutoriales y otras preguntas SO, parece como si

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

Es la clave para conseguir que se actualice, y está ahí, y se llama. Pero nada se actualiza.

Finalmente, mi fragmento de lista que muestra todos los datos.

 package org.worldsproject.android.barcode; import org.worldsproject.android.barcode.database.DatabaseProvider; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.SimpleCursorAdapter; import com.actionbarsherlock.app.SherlockListFragment; public class RunningTotal extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor> { public static final String TAG = "Running Total"; public static final int RUNNING_TOTAL_ID = 1; private SimpleCursorAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] uiBindFrom = { DatabaseProvider.COLUMN_PERSON }; int[] uiBindTo = { R.id.titled }; adapter = new SimpleCursorAdapter( getActivity().getApplicationContext(), R.layout.list_title, null, uiBindFrom, uiBindTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); setListAdapter(adapter); getLoaderManager().initLoader(RUNNING_TOTAL_ID, null, this); } @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { String[] projection = { DatabaseProvider.COLUMN_ID, DatabaseProvider.COLUMN_PERSON}; return new CursorLoader(getActivity(), DatabaseProvider.CONTENT_URI, projection, null, null, null); } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) { // TODO Auto-generated method stub adapter.swapCursor(cursor); } @Override public void onLoaderReset(Loader<Cursor> arg0) { // TODO Auto-generated method stub adapter.swapCursor(null); } } 

Es casi un clon directo de http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ y de momento sólo muestra la columna de nombre de cada fila de la base de datos. Muestra las entradas anteriores, pero como he dicho, no se actualiza. ¿Qué paso me falta para conseguir que se actualice?

Creo que su

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

Puede estar bien.

No puedo ver la función de consulta para su DatabaseProvider, pero ¿recordó establecer la notificaciónUri para el cursor que está regresando en su función de consulta?

En la función query () de DatabaseProvider, debe establecer la Uri de notificación para el cursor o bien el cursor no obtendrá una notificación incluso si hace un notifyChange ():

 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // blah blah cursor.setNotificationUri(getContext().getContentResolver(), uri); } 

Tuve un problema similar con un fragmento usando un buscapersonas. Me di cuenta de que no tenía un ContentObserver registrado, así que lo único que hice fue añadir este código a la onResume ()

 getActivity().getContentResolver().registerContentObserver(sUri, true, myObserver); 

Y tiene myObserver declarado como una variable miembro:

 new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { getActivity().getSupportLoaderManager().restartLoader(); // With appropriate loader args here } }); 

Y asegúrese de anular el registro está en la onPause ();

Que parecía arreglar mi problema, suponiendo que el ContentProvider está llamando notifyChange correctamente (parece que son, sin embargo).

¡Espero que esto te ayude!

Creo que el error está aquí:

 Uri newUri = ContentUris.withAppendedId(CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(uri, null); return newUri; 

Debería llamar al método notifyChange con el uri del elemento que acaba de agregar, que es newUri.

Así que la notificación se convierte en:

 getContext().getContentResolver().notifyChange(newUri, null); 
  • Uso de Ormlite en combinación con el proveedor de contenido de Android
  • ¿Flujo de datos entre Android BroadcastReceiver, ContentProvider y Activity?
  • Cómo definir la frecuencia de las actualizaciones de SyncAdapter en android?
  • Compartir una imagen en el directorio de datos de la aplicación a través de un ContentProvider en Android
  • Android duplica el problema de la autoridad del proveedor
  • Android Obtener el grupo de contactos por ID
  • Android: Ampliación del libro de contactos del usuario. Rendimiento ContentProvider vs Sqlite vs Lista en la memoria
  • Android - Uso del patrón Dao con contentProvider
  • ¿Es posible reemplazar el MediaStore con un doble de prueba usando robolectric?
  • IllegalStateException "intenta volver a abrir un objeto ya cerrado" en SimpleCursorAdapter de ContentProvider
  • Error Cursor.moveToNext
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.