Come sospendere la notifica agli osservatori, mentre facendo molti cambiamenti utilizzando un ContentProvider
-
28-09-2019 - |
Domanda
Ho un ExpandableListView che utilizza una SimpleCursorTreeAdapter che utilizza i cursori restituiti da una ContentProvider. Questo va bene in quanto mantiene sempre in sincronia con i dati ma a volte ho bisogno di fare molti cambiamenti al database in modo che il cursore viene ripetizione molte volte nello stesso secondo. E 'possibile sospendere la notifica di ContentObservers al fine di evitare inutili requerys?
Soluzione
Una possibile soluzione è quella di modificare il fornitore di contenuti per consentire la sospensione delle notifiche. URI da notificare vengono aggiunti a una coda fino a quando la sospensione è disabilitata.
private boolean suspendNotifications = false;
private LinkedList<Uri> suspendedNotifications = new LinkedList<Uri>();
private HashSet<Uri> suspendedNotificationsSet = new HashSet<Uri>();
private void notifyChange(Uri uri) {
if (suspendNotifications) {
synchronized (suspendedNotificationsSet) { // Must be thread-safe
if (suspendedNotificationsSet.contains(uri)) {
// In case the URI is in the queue already, move it to the end.
// This could lead to side effects because the order is changed
// but we also reduce the number of outstanding notifications.
suspendedNotifications.remove(uri);
}
suspendedNotifications.add(uri);
suspendedNotificationsSet.add(uri);
}
}
else {
getContext().getContentResolver().notifyChange(uri, null);
}
}
private void notifyOutstandingChanges() {
Uri uri;
while ((uri = suspendedNotifications.poll()) != null) {
getContext().getContentResolver().notifyChange(uri, null);
suspendedNotificationsSet.remove(uri);
}
}
private void setNotificationsSuspended(boolean suspended) {
this.suspendNotifications = suspended;
if (!suspended) notifyOutstandingChanges();
}
@Override
public Uri insert(Uri uri, ContentValues values) {
...
notifyChange(uri);
return newItemUri;
}
Non sono sicuro di come meglio abilitare / disabilitare la sospensione, ma una possibilità sarebbe quella di avere uno speciale URI che accende / off sospensione (ad esempio il contenuto: //
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
switch (uriMatcher.match(uri)) {
...
case SUSPEND:
boolean enabled = values.getAsBoolean("enabled");
setNotificationsSuspended(enabled);
break;
...
}
}
Il servizio che fa i cambiamenti al database può ora sospendere la ContentProvider quando inizia e la sospensione disabilita quando finisce.
Altri suggerimenti
Si può utilizzare http: // sviluppatore .android.com / riferimento / android / widget di / BaseAdapter.html # unregisterDataSetObserver (android.database.DataSetObserver ) per annullare la registrazione i vostri ascoltatori e una volta che il vostro lavoro è pronto, registrare di nuovo loro? Suona come un AsyncTask per me.