¿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 .

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 ?

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 .

  • La base de datos Android está dañada, pero puede abrirse en SQLite Manager. ¿Recuperable?
  • Base de datos de diccionarios sin conexión para la aplicación de Android
  • Almacenar valores dobles en SQLite: ¿cómo asegurar la precisión?
  • Ejemplo de Android SQLite
  • Android: ¿Hay una mejor manera de insertar y / o actualizar una entrada de base de datos?
  • SQLiteOpenHelper - ¿Cómo se crea la base de datos?
  • Mejores prácticas para seleccionar una base de datos para aplicaciones móviles
  • Se filtró un objeto SQLiteConnection para la base de datos. Por favor, corrija su aplicación
  • Logcat error Index -1 solicitado, con un tamaño de 24
  • Android.database.sqlite.SQLiteException: Token no reconocido:
  • ¿Por qué mi Cursor no está cerrado en una actividad de Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.