开发者

How to suspend notification to observers while doing many changes using a ContentProvider

I have an ExpandableListView that uses a SimpleCursorTreeAdapter which uses the cursors returned by a ContentProvider. This is fine as it always keeps in sync with the data but sometime开发者_开发知识库s I need to do many changes to the database so that the cursor is requeried many times in the same second. Is it possible to suspend the notification of ContentObservers to avoid unnecessary requerys?


A possible solution is to modify the content provider to allow suspending notifications. URIs to be notified are added to a queue until suspension is disabled.

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

I'm not sure how to best enable/disable suspension but one possibility would be to have a special URI which turns on/off suspension (e.g. content://<authority>/suspension) in the update() method:

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

The service that does the changes to the database can now suspend the ContentProvider when it starts and disable suspension when it finishes.


Can you use http://developer.android.com/reference/android/widget/BaseAdapter.html#unregisterDataSetObserver(android.database.DataSetObserver) to unRegister your listeners and once your work is ready, register them again? Sounds like a AsyncTask to me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜