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.
- Compartir imágenes desde el almacenamiento interno mediante FileProvider
- La consulta ContentResolver está lanzando una excepción nullpointerException
- Reutilización de código lógico entre aplicaciones para Android y otras plataformas: ¿Para ContentProvider o no para ContentProvider?
- Los proveedores de contenidos exportados pueden proporcionar acceso a datos potencialmente confidenciales
- SelectionArgs in ContentResolver.query (...) puede ser una subconsulta?
@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?
- Own ContentProvider con SQLite y varias tablas
- Adición de un tipo de mime personalizado a los contactos de android
- ¿Cómo puedo capturar el proveedor de contenido inicializar?
- ¿Por qué debo usar un proveedor de contenido personalizado en Android?
- Android sqlite "base de datos está bloqueado" errores a pesar del uso de proveedor de contenido y acceso a bases de datos secuenciales
- Agrupar por en ContentResolver en Ice Cream Sandwich
- ¿Cómo ejecutar un servicio singleton (compartido) en una biblioteca para múltiples aplicaciones?
- Android múltiples proveedores de contenido, (DLC)
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);
- ¿Cómo configurar las imágenes del sistema (ruta?) Al crear un Android AVD?
- Android – android.view.InflateException con una vista personalizada