1. 程式人生 > >Use Android's ContentObserver in Your Code to Listen to Data Changes

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.

相關推薦

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'

How to Correctly Use SQL's like in Android

Yesterday I stumbled about the correct usage of the LIKE-statement in conjunction with selectionArgs. My first attemp

MySQL Workbench導出Model提示['ERROR 1064 (42000): You have an error in your SQL syntax....syntax to use near 'VISIBLE']

mysq ack targe war har nds 查看 -c int CREATE TABLE IF NOT EXISTS `pihealth`.`warning_events` ( `wid` INT NOT NULL AUTO_INCREMENT,

解決author波浪線Spellchecker inspection helps locate typos and misspelling in your code, comments and literals, and fix them in one click

博客 翻譯 cli 修復 and idea tro alt 拼寫檢查 自從把默認的頭註釋的author改成自己的名字以後越看越順眼,但是發現名字下面一直有個波浪線,強迫癥簡直不能忍。 然後當你把鼠標放上去,再點擊提示上的“more”,會看到下面的提示: Spellchec

pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your path

目錄 BUG: 原因: 下載: 完美解決 BUG:  File "D:\python\lib\site-packages\pytesseract\pytesseract.py", line 172, in run_tesseract   &n

spellchecker inspection helps locate typos and misspelled in your code,comments and l

使用自己的名字當Tag。卻發現有個非常不用好的提示。   Typo:In word ‘miyuehu’ less...(Ctrl+F1) spellchecker inspection helps locate typos and misspelled in your c

Ask HN: How do you use internal project codenames in your company?

We use them and I complain about it a lot. Anything that reduces clarity and transparency is a bad thing in my opinion - a codename is at best security the

How To Use Retrofit Library In Your Android App

Retrofit library is a Type-safe REST client for android and Java, courtesy of Square Inc. Most modern android apps make HTTP requests to some remote s

<轉>How to Encourage Your Child's Interest in Science and Tech

sim challenge table nic options https fun developed advice How to Encourage Your Child‘s Interest in Science and Tech This week’s Ask-A-D

Error Code : 1064 You have an error in your SQL syntax; check the manual that corresponds to your My

轉自:https://blog.csdn.net/haha_66666/article/details/78444457 Query : select * from order LIMIT 0, 1000 Error Code : 1064 You have an error in your

解決ROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use n

之前一直用的好好的,突然就出現了這個錯誤: ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the rig

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'grou

mysql8.0版本  在已存在的表裡插入一條資料 insert INTO api_user(id,username,email,groups)VALUES('1','hh','[email protected]','Boss'); 執行報錯:1064 - You have an e

myBatis查詢報錯 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

myBatis查詢報錯    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

Why (and how) to use eslint in your project

Why (and how) to use eslint in your projectThis story was written by Sam Roberts, a Senior Software Engineer at IBM Canada. It was first published in IBM d

4 Powerful Ways to Use AI in Your Advertising

Mike Kaput is a senior consultant at PR 20/20 who is passionate about AI's potential to transform marketing. At PR 20/20, he creates measurable marketing r

How to use Android Studio's SVG-to-VectorDrawable converter from the command line

Since the very beginning, one of the most annoying aspects of using VectorDrawables on Android has been the lack of a reliable SVG converter. Goog

Use CloudTrail to Review What Actions Occurred In Your AWS Account

AWS CloudTrail enables you to view and track API calls made to your account. CloudTrail data can be accessed with the AWS Management

java.sql.SQLException: Your password has expired. To log in you must change it using a client that s

java.sql.SQLException: Your password has expired.To log in you must change it using a client that supports expired passwords. com.mysql.jdbc.exceptions.j

安裝Android studio出現'tools.jar' seems to be not in Android Studio classpath......的解決方法

eas 一個 origin java_home ems view 使用 分享 title 安裝Android studio出現‘tools.jar‘ seems to be not in Android Studio classpath......的解決方法 原創 201