ContentObserver是android上监听内容变化的常用工具,既可以监听本应用的,也可以监听其他应用的内容变化。通常有两种用法:
- ContentResolver.registerContentObserver(Uri uri, ContentObserver observer):
用于监听指定uri的内容变化 - Cursor.registerContentObserver(ContentObserver observer):
用于监听指定cursor指向的内容变化
那么监听器是如何注册的?通知又是如何发出来的呢?先看下通过ContentResovler注册的方式
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer, int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle);
} catch (RemoteException e) {
}
}
可以看到, 这里首先通过getContentService()获取获取了一个ContentService的系统服务,然后获取了observer的一个binder对象,并注册给ContentService。
再看下getContentSerivce的是实现:
/** @hide */
public static IContentService getContentService() {
if (sContentService != null) {
return sContentService;
}
IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
if (false) Log.v("ContentService", "default service binder = " + b);
sContentService = IContentService.Stub.asInterface(b);
if (false) Log.v("ContentService", "default service = " + sContentService);
return sContentService;
}
可以看到ContentService确实是注册在ServiceManager中的一个系统服务。到这里就可以确认ContentResolver注册ContentPrvider是将一个Binder的回调对象注册到了SystemServer的ContentService中了,所以不需要被监听的内容必须在运行。
那么通知是如何实现的呢?
通过ContentReslover的notifyChange(Uri uri)实现,
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(), syncToNetwork,
userHandle);
} catch (RemoteException e) {
}
}
也就是说注册和通知其实都是通过ContentService解耦了,通知方不用有多少人注册了,只需要向ContentService发送一个内容改变的通知即可,通过uri告诉ContentService那部分内容发生来改变,ContentService再向所有的注册该uri ContentObserver的进程发送通知。
接下来再看看Cursor是怎么注册的?
一般而言,Cursor是通过ContentProvider查询返回的,这就涉及到两种情况:
- 跨进程查询返回到Cursor
- 本进程查询返回的Cursor
对于跨进程查询返回的Cursor,在ContentProviderNative的onTransact方法中就已经注册了一个caller的ContentObserver调用,后续的注册只需要在caller进程增加本地的ContentObserver对象即可
对于本进程查询,直接注册本地ContentObserver即可.
但是!Cursor注册了ContentObserver之后,只能在Cursor变化的时候通知监听者,而Cursor本身并不能监听内容变化,所有要实现监听,必须调用setNotificationUri(ContentResolver resolver, Uri uri)
AbstractCursor.java
public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) {
synchronized (mSelfObserverLock) {
mNotifyUri = notifyUri;
mContentResolver = cr;
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
mSelfObserver = new SelfContentObserver(this);
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle);
mSelfObserverRegistered = true;
}
}
所以,Cursor的注册其实也是通过ContentResolver完成
综上: 无论通过ContentResolver还是Cursor注册ContentObserver,其注册与通知都是通过SystemServer的ContentService完成,即使要监听的内容都在本进程中,也会通过binder调用完成通知。