android - teclado - usar celular como mouse via usb
¿Para qué se utiliza el cursor.setNotificationUri()? (3)
Hice una investigación sobre cómo usar ContentProviders
y Loaders en 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);
a través de un botón de clic.
En nuestra implementación de ContentProvider
, al final del método insert()
, llamamos getContentResolver().notifyChange(URI, null);
y nuestro CursorLoader
recibirá un mensaje de que debe recargar los datos y actualizar la interfaz de usuario. Además, si usamos FLAG_REGISTER_CONTENT_OBSERVER
en SimpleCursorAdapter
, también recibirá un mensaje y se onContentChanged()
su método onContentChanged()
.
Por lo tanto, nuestro ListView se actualizará si insertamos, actualizamos o eliminamos datos.
Activity.startManagingCursor(cursor);
está en desuso, cursor.requery()
desuso, por lo que no veo ningún sentido cursor.setNotificationUri()
de cursor.setNotificationUri()
.
Busqué en 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 el cursor recibirá un mensaje y se llamará al siguiente método dentro del Cursor:
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange, null);
// ...
}
}
Pero no puedo darle sentido a esto.
Entonces, mi pregunta es: ¿por qué deberíamos llamar cursor.setNotificationUri()
en el método de query()
de nuestra implementación ContentProvider
?
Si llama a Cursor.setNotificationUri()
, el Cursor sabrá para qué ContentProvider Uri fue creado.
CursorLoader
registra su propio ForceLoadContentObserver
(que extiende ContentObserver
) con el ContentResolver
de ContentResolver
para el URI que especificó al llamar a setNotificationUri
.
Entonces, una vez que ContentResolver
sepa que el contenido de URI ha cambiado [esto sucede cuando llama a getContext().getContentResolver().notifyChange(uri, contentObserver);
dentro de los métodos Insert insert()
, update()
y delete()
ContentProvider
, notifica a todos los observadores, incluido ForceLoadContentObserver de ForceLoadContentObserver
.
ForceLoadContentObserver
luego marca mContentChanged del cargador como verdadero
Yo uso un URI para el adaptador de 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, uso un URI diferente para cambiar el contenido de la base de datos . Para actualizar mi vista, tuve que cambiar la implementación predeterminada del método de update
del proveedor de datos. La implementación predeterminada solo notifica el mismo URI. Tengo que notificar a otro URI.
Terminé llamando a la 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
.
CursorLoader
registra el observador para el cursor, no para el URI.
Mire 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
debe 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 de insert
, update
y delete
getContext().getContentResolver().notifyChange(uri, null);
, debe llamar a getContext().getContentResolver().notifyChange(uri, null);
Para notificar cambios a los observadores uri
.
Entonces, si no llama al cursor#setNotificationUri()
, su CursorLoader
no recibirá una notificación si los datos subyacentes a esa uri
cambian.