1

J'ai un ExpandableListView qui utilise un SimpleCursorTreeAdapter qui utilise les curseurs renvoyés par un ContentProvider. C'est très bien car il reste toujours synchronisé avec les données mais parfois j'ai besoin de faire beaucoup de changements dans la base de données pour que le curseur soit réitéré plusieurs fois dans la même seconde. Est-il possible de suspendre la notification de ContentObservers pour éviter les requerys inutiles?Comment suspendre la notification aux observateurs tout en effectuant de nombreuses modifications à l'aide d'un ContentProvider

Répondre

1

Une solution possible consiste à modifier le fournisseur de contenu pour autoriser la suspension des notifications. Les URI à notifier sont ajoutés à une file d'attente jusqu'à ce que la suspension soit désactivée.

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; 
} 

Je ne sais pas comment activer mieux/désactiver la suspension, mais une possibilité serait d'avoir un URI spécial qui se suspension on/off (par exemple le contenu: // < autorité >/suspension) dans la mise à jour() méthode:

@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; 
    ... 
    } 
} 

le service qui fait les modifications apportées à la base de données peut maintenant suspendre le ContentProvider quand il démarre et suspension désactiver quand il se termine.

0

Pouvez-vous utiliser http://developer.android.com/reference/android/widget/BaseAdapter.html#unregisterDataSetObserver(android.database.DataSetObserver) pour unRegister vos auditeurs et une fois que votre travail est prêt, enregistrez-les à nouveau? Cela ressemble à un AsyncTask pour moi.

+0

Ce n'est pas possible. Les auditeurs pourraient être n'importe où et l'application pourrait être dans n'importe quel état. Les modifications de la base de données sont effectuées dans un service distant. En outre, je ne pense pas qu'il soit possible de désenregistrer les observateurs d'un SimpleCursorTreeAdapter, ce qui signifie que j'ai dû créer un adaptateur personnalisé. – Tom

+0

Est-ce que tout cela est dans votre propre application? –

+0

Désolé trop rapide envoyé pour le dernier commentaire. Avez-vous envisagé d'ajouter un autre observateur pour savoir si une classe de client devrait écouter ou non et vous pouvez aussi essayer de faire le travail de base de données lourd via SQLite directement et envoyer un appel de mise à jour 1 = 1 lorsque vous avez terminé. –