ContentObserver 원리

3678 단어
ContentObserver는android에서 내용 변화를 감청하는 데 자주 사용하는 도구로 이 앱도 감청할 수 있고 다른 앱의 내용 변화도 감청할 수 있다.일반적으로 두 가지 용도가 있습니다.
  • ContentResolver.registerContent Observer(Uri uri, Content Observer observer): 지정한 uri의 내용 변화를 감청하는 데 사용
  • Cursor.registerContent Observer(Content Observer 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) {
        }
    }
    

    보시다시피 getContent Service () 를 통해 Content Service의 시스템 서비스를 얻은 다음에 observer의binder 대상을 가져와 Content Service에 등록합니다.그리고 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가 Service Manager에 등록된 시스템 서비스인지 확인할 수 있습니다.Content Resolver 등록 Content Prvider는 Binder의 리셋 대상을 System Server의 Content Service에 등록했기 때문에 감청할 필요가 없는 내용이 실행되어야 합니다.그렇다면 통지는 어떻게 이루어졌을까?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) {
            }
        }
    

    즉, 등록과 알림은 모두 Content Service를 통해 해결된다. 알림자는 몇 명이 등록하지 않아도 된다. Content Service에 내용 변경 알림을 보내면 된다. uri를 통해 Content Service의 일부 내용이 변경되었다고 알려주면 된다. Content Service는 이uri Content Observer를 등록하는 모든 프로세스에 알림을 보낸다.
    이제 커서가 어떻게 등록했는지 볼까요?일반적으로 Cursor는 ContentProvider 질의를 통해 반환되므로 두 가지 조건이 있습니다.
  • 프로세스 간 질의가 Cursor
  • 로 반환됨
  • 이 프로세스 질의에서 반환된 Cursor
  • 크로스 프로세스 조회가 되돌아오는cursor에 대해Content Provider Native의onTransact 방법에서caller의Content Observer 호출을 등록했습니다. 후속 등록은caller 프로세스에서 로컬의Content Observer 대상을 추가하면 본 프로세스 조회에 대해 로컬Content Observer에 직접 등록하면 됩니다.하지만!Cursor는Content Observer에 등록한 후 Cursor가 변할 때만 감청자에게 알릴 수 있지만 Cursor 자체는 내용 변화를 감청할 수 없습니다. 모든 감청을 실현하려면 setNotificationUri(Content Resolver resolver, 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;
            }
        }
    

    그래서 커서의 등록도 사실은Content Resolver를 통해 이루어졌습니다.
    요약: Content Resolver든Cursor를 통해Content Observer를 등록하든 그 등록과 알림은 시스템서버의Content Service를 통해 이루어지며 감청할 내용이 이 프로세스에 있더라도 binder를 통해 알림을 호출합니다.

    좋은 웹페이지 즐겨찾기