Use Android’s ContentObserver in Your Code to Listen to Data Changes

When you are using a content provider as a client, chances are that you want to know whenever the data changes. That’s what Android’s class ContentObserver is for.

To use the ContentObserver you have to take two steps:

  • Implement a subclass of ContentObserver
  • Register your content observer to listen for changes

Implement a subclass of ContentObserver

ContentObserver is an abstract class with no abstract methods. Its two onChange() methods are implemented without any logic. And since these are called whenever a change occurs, you have to override them.

Since Google added one of the two overloaded onChange() methods as recently as API-level 16, this method’s default behavior is to call the other, older method.

Here is, what a normal implementation would look like:

@SuppressLint("NewApi")
class MyObserver extends ContentObserver {		
   public MyObserver(Handler handler) {
      super(handler);			
   }

   @Override
   public void onChange(boolean selfChange) {
      this.onChange(selfChange, null);
   }		

   @Override
   public void onChange(boolean selfChange, Uri uri) {
      // do s.th.
      // depending on the handler you might be on the UI
      // thread, so be cautious!
   }		
}

Some things are important with the above code. The first thing you must know, is that the second method is only available from API level 16 onwards. That’s why I added the SuppressLint annotation. The code works fine on older devices, but in this case Android obviously always calls the old one. So your code should not rely on a URI to work properly.

Also notice the Handler parameter in the constructor. This handler is used to deliver the onChange() method. So if you created the Handler on the UI thread, the onChange() method will be called on the UI thread as well. In this case avoid querying the ContentProvider in this method. Instead use an AsyncTask or a Loader.

If you pass a null value to the constructor, Android calls the onChange() method immediately – regardless of the current thread used. I think it’s best to always use a handler when creating the ContentObserver object.

Register your content observer to listen for changes

To register your ContentObserver subclass you simply have to call the ContentResolver's registerContentObserver() method:

getContentResolver().
      registerContentObserver(
            SOME_URI, 
            true, 
            yourObserver);

It takes three parameters. The first is the URI to listen to. I cover the URI in more detail in the next section.

The second parameter indicates whether all changes to URIs that start with the given URI should trigger a method call or just changes to exactly this one URI. This can be handy for say the ContactsContract URI with its many descendants. But it can also be detrimental in that the actual change, that caused the method call, is even more obscure to you.

The third parameter is an instance of your ContentObserver implementation.

The URIs you can observe

As described in my introduction to content providers content URIs can be directory-based or id-based.

Both of these URI-types can be used for your content observer. If you have a detail screen you would use an id-based URI for your observer, and when you use a list of data a directory-based URI is more appropriate.

This does not always work, though. ContactsContract for example always triggers a change, whenever any contact was changed, even if you are listening to a more specific URI. It depends on the correct implementation of the content provider. I have filed a bug report for the ContactsContract provider. Please vote for this issue, if you agree.

When you write a content provider for your app, take care of notifying the correct URI. Only if you do so, the feedback mechanism described here works. This is important for your observers – or if the provider is exported for your clients’ observers as well. And it is also important for Loaders. See my post about how to write content providers to learn more about this.

Note: If you use Loaders you do not need to listen to changes yourself. In this case Android registers a ContentObserver and triggers your LoaderCallbacks onLoadFinished() method for any changes.

Do not forget to unregister your content observer

When you have registered a content observer, it is your responsibility to also unregister it. Otherwise you would create a memory leak and your Activity would never be garbage collected.

To unregister you call the unregisterContentObserver() method of the ContentResolver:

getContentResolver().
      unregisterContentObserver(yourObserver);

You register your observer in the onResume() lifecycle method and you unregister it in the onPause() method.

This is not relevant to ContentObservers alone but applies to everything you register. As a general rule of thumb: Whenever you start coding registerXYZ() immediately also add the code to unregisterXYZ(). Otherwise you might later forget about it and inadvertently create memory leaks.

Sometimes you wish you would know more about the changes

The main downside with content observers is, that you do not get any additional information about what has changed. For directory-based URIs it would be nice to get a list of IDs that have changed. Some providers can have many records and re-reading all records, if only a few have changed, is a waste of resources in a mobile environment. Also some hint of the type of change would be nice. Like if a record was deleted or inserted.

The ContentProvider responsible for the change knows all this. So this would be no problem to add. Of course it has to be added in a backwards-compatible way.

API level 16 added a URI to the onChange() method, but this isn’t sufficient for updates of multiple records and also doesn’t tell you anything about the type of change.

Wrapping up

This quick tip showed you how to leverage Android’s ContentObserver. This makes it easy to react to updates of the data you are using.

As you have seen, it is pretty easy to implement the ContentObserver subclass. You have also seen that you can register it to listen to id-based as well as directory-based URIs.

Of course this works only, if the content provider for the URI you are observing, is correctly implemented and notifies clients of changes. If you are implementing a content provider yourself, have a look at my tutorial on writing a content provider for how to do so.

Share this article:

You can leave a response, or trackback from your own site.

13 Responses to “Use Android’s ContentObserver in Your Code to Listen to Data Changes”

  1. Oz says:

    Doesn’t one need this only when not using Loaders?

    • Yes. As I have stated in the post, you do not need content observers for data that you have loaded via Loaders.

      But there might still be a need for them, if you need to know about changes of other data like some data of the in-built content providers. Or if fields in your database link to fields of the standard providers (e.g. the lookup uri of a contact).

      • Ashok says:

        Hi Wolfram,

        Thanks for the great post! I noticed that you mentioned that if I use a Loader (i.e. a CursorLoader) I don’t need to register a ContentObserver. However, I’ve noticed that in my app, I have an activity that simply emulates a submission form. When the user hits submit, it makes an insertion into the database table and calls finish(), which resumes my previous activity, which is displaying results from that same database table. However, the LoaderCallbacks aren’t being called automatically. I’ve had to explicitly put the initLoader() call in my onResume() method. Is this expected?

  2. Peri Hartman says:

    Wolfram, your post was very helpful. I just got my content observer for contacts working – to the extent that it notifies my app when a contact changes. Hurray!

    I’d like to point out a clarification that may also help others. I found your call:

    this.onChange(selfChange, null)

    ambiguous, not being sure what “this” is (in my code, it turned out to be the observer, which caused a stack overflow). What worked for me is

    handler.sendMessage (msg)

    where “msg” is whatever info you want to pass to your activity. In total, I used this code:

    @Override
    public void onChange (boolean selfChange)
    {
    Message msg = handler.obtainMessage();
    msg.what = CONTACTS_CHANGED; // final int defined elsewhere
    msg.obj = null;
    handler.sendMessage (msg);
    }

    My next challenge is figuring out how to detect which contact was changed. As you said, the provider does not give you anything :(

    I hope you find this useful.

  3. doss says:

    Hi

    when ever there is changes in setting for when we changes the state of Bluetooth it should raise alert and revert back to old state. can u help me in this .

  4. Olumide says:

    Hi,
    Supposing I use Supposing I use AsyncTaskLoader, do I need to register a ContentObserver?
    Also, how do I register content observer for my database.

    Thanks

    • ContentObservers are only for content providers. If you use SQLite directly and have a custom AsyncTaskLoader implementation you cannot use it – but you might want to look at Mark Murhpy’s SQLiteCursorLoader. Even if you do not want to use this library have a look at the sources to see how he implements this with a Loader.

      If you have multiple place that might be interested in content changes an event bus solution might be handy. Use one db abstraction to only change the database from there and have all modification methods submit an event bus notification. See Otto or EventBus for more on this.

  5. Mohamed Elmanasrah says:

    thanks for good informations

  6. Jobin says:

    Hi Wolfram,
    Thanks for the useful post. Have a doubt in my particular case on how or whether to use a ContentObserver. ( Might be a silly question but please bear with me as I m new into Android ).

    I have used a Loader to Load the Contacts from DB asynchronously. Before loading I will be checking the ContactsUri Contacts whether they are registered users with mobile numbers. So basically the workflow is like Loading all the contents from Content provider , check with SQLite Db if not exist insert. Then Read this User Contacts from DB through a loader asynchronisly. Now , what I need is to get notified to the App whether there is any change for the Contacts in the Phone if so trigger the update to DB.

    Can you please let me know if I can use the same logic here

    • There is no proper solution for that – because any long-running service would require an ongoing notification. Unless the user cares very much about what the service does, this is not recommended. So in your case: Don’t do that!

      Some ways to mitigate it, would be to periodically check for changes. But, please, use one of the non-wakeup types in your AlarmManager. (RTC or ELAPSED_REALTIME). There is no need to wake up a device for these checks. If you expect changes to happen frequently and your app must be correct, there is no other way than to additionally also check at app startup time (that is in your Application subclass). Asynchronously, of course :-)

      While you app is running you can listen to the events in your Application subclass. So the AlarmManager is only necessary when your app is not running. See my tutorial about (un)registering BroadcastReceivers in code.

Leave a Reply

You can also subscribe without commenting.

Subscribe to RSS Feed My G+-Profile Follow me on Twitter!