ContentObserver原理

ContentObserver是android上监听内容变化的常用工具,既可以监听本应用的,也可以监听其他应用的内容变化。通常有两种用法:

  1. ContentResolver.registerContentObserver(Uri uri, ContentObserver observer):
    用于监听指定uri的内容变化
  2. 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查询返回的,这就涉及到两种情况:

  1. 跨进程查询返回到Cursor
  2. 本进程查询返回的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调用完成通知。

你可能感兴趣的:(ContentObserver原理)