question

Jeffrey Blattman avatar image
Jeffrey Blattman asked Jeffrey Blattman answered

How do I handle duplicate callbacks with content observers?

When I register a content observer, I get called back multiple times (sometimes many times) when the database changes. I only want one notification when database updates are complete. How can I achieve this?
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

Jeffrey Blattman avatar image
Jeffrey Blattman answered
This is a common problem. While it depends on the content provider implementation, every insert, update, or delete in the content provider will most likely trigger a notification. Moreover, the code that is mutating the database may choose to perform multiple database operations for a single logical update ... each of which will trigger a notification.

There is also the situation where an entire database is re-synced periodically. Imagine a naive sync algorithm that downloads the entire data set from the server each time the data is synced. This will at least generate one notification for each row synced.

This is probably not what you want as a client. You want to know when whatever is updating the database is "done", so you can update your state accordingly. You definitely do not want to continually update your state after every mutation to the database.

To handle this, you can use Handler's post delayed mechanism. In a nutshell, you delay handling the notification until some amount of time passes where you have not received any notifications. For example,

public class DelayedObserver extends ContentObserver {
  private final Handler processHandler = new Handler(Looper.getMainLooper());

  private final Runnable work;  
  private final long delay;

  public QueueObserver(Runnable work, long delay) {
    super(processHandler);
    this.work = work;
    this.delay = delay;
  }

  @Override
  public void onChange(boolean selfChange) {
    processHandler.removeCallbacksAndMessages(null);
    processHandler.postDelayed(work, delay);
  }
}

The value for "delay" will need to be tuned according to what you are observing. I've found values of 250ms generally work well. Obviously larger values will introduce delays in updating your state, while smaller values will increase the likelihood of duplicate updates.
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Welcome to the
Clover Developer Community