¿Para qué se utiliza cursor.setNotificationUri ()?
Hice una investigación sobre cómo usar ContentProviders
y Loaders de este tutorial
Cómo lo veo: Tenemos una Activity
con ListView
, SimpleCursorAdapter
y CursorLoader
. También implementamos ContentProvider
.
- Creación de una clase de modelo de datos para el manejo de bases de datos
- Error - android.database.CursorIndexOutOfBoundsException: Índice 0 solicitado, con un tamaño de 0
- Consulta de mejores prácticas de SQLite para Android
- Error de base de datos SQLite de SQL cuando intenta insertar en la tabla
- Android: actualizar la versión de la base de datos y agregar nueva tabla
En una Activity
podemos llamar a getContentResolver().insert(URI, contentValues);
Mediante un clic de botón.
En nuestra implementación de ContentProvider
en el método insert () que llamamos getContentResolver().notifyChange(URI, null);
Y nuestro CursorLoader
recibirá el mensaje de que debe recargar los datos y actualizar la interfaz de usuario. También si usamos FLAG_REGISTER_CONTENT_OBSERVER
en SimpleCursorAdapter
también recibirá mensaje y su método onContentChanged()
será llamado.
Así que nuestro ListView se actualizará si insertamos, actualizamos o eliminamos datos.
Activity.startManagingCursor(cursor);
Está obsoleto, cursor.requery()
desaprobado, así que no veo ningún sentido cursor.setNotificationUri()
de cursor.setNotificationUri()
.
Miré el código fuente del método setNotificationUri()
y vi que llama a mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver)
dentro del método. También CursorLoader
hace lo mismo. Finalmente cursor recibirá mensaje y el siguiente método será llamado dentro de Cursor:
protected void onChange(boolean selfChange) { synchronized (mSelfObserverLock) { mContentObservable.dispatchChange(selfChange, null); // ... } }
Pero no puedo entender esto.
Así que mi pregunta es: ¿por qué deberíamos llamar cursor.setNotificationUri()
en el método query()
de nuestra implementación ContentProvider
?
- Android: ¿Cómo crear mi propia clase de cursor?
- Las clases de modelo de dominio deben extender RealmObject o implementar RealmModel para que se considere una clase de modelo válida
- La manera más rápida y eficiente de pre-poblar la base de datos en Android
- Error de Android sql al usar SUM
- Android: No se puede realizar esta operación porque se ha cerrado el grupo de conexiones
- Android: java.lang.IllegalStateException: base de datos xxx.db (conn # 0) ya cerrado
- Sqlite Comprobar si la tabla está vacía
- Cómo comprobar si un usuario está iniciando sesión por primera vez con Firebase Authentification
Si llama a Cursor.setNotificationUri()
, Cursor sabrá para qué ContentProvider Uri fue creado.
CursorLoader
registra su propio ForceLoadContentObserver
(que extiende ContentObserver
) con ContentObserver
del Context
para el URI que especificó al llamar a setNotificationUri
.
Así que una vez que ContentResolver
sabe que el contenido de URI ha sido cambiado [esto sucede cuando usted llama getContext().getContentResolver().notifyChange(uri, contentObserver);
Dentro de los métodos insert()
, update()
y delete()
ContentProvider
notifica a todos los observadores incluyendo ForceLoadContentObserver de ForceLoadContentObserver
.
ForceLoadContentObserver
entonces marca mContentChanged de Loader como true
CursorLoader
registra al observador del cursor, no al URI.
Busque en el código fuente de CursorLoader a continuación. Observe que CursorLoader
registra contentObserver
en el cursor
.
/* Runs on a worker thread */ @Override public Cursor loadInBackground() { synchronized (this) { if (isLoadInBackgroundCanceled()) { throw new OperationCanceledException(); } mCancellationSignal = new CancellationSignal(); } try { Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder, mCancellationSignal); if (cursor != null) { try { // Ensure the cursor window is filled. cursor.getCount(); cursor.registerContentObserver(mObserver); } catch (RuntimeException ex) { cursor.close(); throw ex; } } return cursor; } finally { synchronized (this) { mCancellationSignal = null; } }
El Cursor
necesita llamar al método setNotificationUri()
para registrar mSelfObserver
en el uri
.
//AbstractCursor.java public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) { synchronized (mSelfObserverLock) { mNotifyUri = notifyUri; mContentResolver = cr; if (mSelfObserver != null) { mContentResolver.unregisterContentObserver(mSelfObserver); } mSelfObserver = new SelfContentObserver(this); mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle); // register observer to the uri mSelfObserverRegistered = true; } }
Dentro de los métodos insert
, update
, delete
getContext().getContentResolver().notifyChange(uri, null);
, necesitas llamar a getContext().getContentResolver().notifyChange(uri, null);
Para notificar el cambio a los observadores uri
.
Así que si no llama al cursor#setNotificationUri()
, su CursorLoader
no recibirá notificación si los datos subyacentes a ese uri
cambian.
Utilizo un URI para el adaptador del cursor.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = new Bundle(); Uri uri = TemperatureContract.SensorEntry.buildSensorID0AddressUri(mDeviceAddress); args.putParcelable("URI", uri); getSupportLoaderManager().initLoader(0, args, this); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { if (args != null) { Uri mUri = args.getParcelable("URI"); return new CursorLoader(this, mUri, null, // projection null, // selection null, // selectionArgs null); // sortOrder } else { return null; } }
En otra clase, utilizo un URI diferente para cambiar el contenido de la base de datos . Para tener mi vista actualizada, tuve que cambiar la implementación predeterminada del método de update
del proveedor de datos. La implementación predeterminada sólo notifica el mismo URI. Tengo que notificar otro URI.
Terminé llamando a notifyChange()
dos veces en mi clase de proveedor de datos, en el método de update
:
@Override public int update( Uri uri, ContentValues values, String selection, String[] selectionArgs) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); int rowsUpdated; switch (match) { case ...: break; case SENSOR_BY_ID_AND_ADDRESS: String sensorId = TemperatureContract.SensorEntry.getSensorIdFromUri(uri); String sensorAddress = TemperatureContract.SensorEntry.getSensorAddressFromUri(uri); rowsUpdated = db.update( TemperatureContract.SensorEntry.TABLE_NAME, values, "sensorid = ? AND address = ?", new String[]{sensorId, sensorAddress}); if (rowsUpdated != 0) { Uri otheruri = TemperatureContract.SensorEntry.buildSensorID0AddressUri(sensorAddress); getContext().getContentResolver().notifyChange(otheruri, null); } break; case ...: break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } if (rowsUpdated != 0) { getContext().getContentResolver().notifyChange(uri, null); } return rowsUpdated;
Hice lo mismo para los métodos de insert
y delete
.
- ¿Qué compilador utiliza Android NDK?
- El dispositivo Android emulado no vuelve a sincronizar la hora / fecha después de restaurar la instantánea