ContentObserver 的原理

ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。

我们可以通过UriMatcher类注册不同类型的Uri,我们可以通过这些不同的Uri来查询不同的结果。根据Uri返回的结果,Uri Type可以分为:返回多条数据的Uri、返回单条数据的Uri。

注册/取消注册ContentObserver方法,抽象类ContentResolver类中的方法原型如下:
public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。
参数:uri,需要观察的Uri(需要在UriMatcher里注册,否则该Uri也没有意义了)
notifyForDescendents 为false 表示精确匹配,即只匹配该Uri为true 表示可以同时匹配其派生的Uri,
observer ContentObserver的派生类实例
举例如下:
假设UriMatcher 里注册的Uri共有一下类型:
1 、content://com.qin.cb/student (学生)
2 、content://com.qin.cb/student/#
3、content://com.qin.cb/student/schoolchild(小学生,派生的Uri)

假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的 Uri 为content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到,但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。

public final void unregisterContentObserver(ContentObserver observer)
功能:取消对给定Uri的观察
参数: observer ContentObserver的派生类实例

ContentObserver类介绍:
构造方法 public void ContentObserver(Handler handler)
说明:所有ContentObserver的派生类都需要调用该构造方法
参数: handler  Handler对象。可以是主线程Handler(这时候可以更新UI了),也可以是任何Handler对象。
常用方法:void onChange(boolean selfChange)
功能:当观察到的Uri发生变化时,回调该方法去处理。所有ContentObserver的派生类都需要重载该方法去处理逻辑。
参数:selfChange 回调后,其值一般为false。

观察特定Uri的步骤如下:
1、创建我们特定的ContentObserver派生类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现。
2、利用context.getContentResolover()获得ContentResolove对象,接着调用registerContentObserver()方法去注册内容观察者。
3、由于ContentObserver的生命周期不同步于Activity和Service等,因此,在不需要时,需要手动的调用unregisterContentObserver()去取消注册。

实现原理:

内容观察者实现:

private ContentObserver mUnreadCallChangeObserver = new ContentObserver(new Handler()) {

    @Override

    public void onChange(boolean selfChange) {

        int num = readMissCall();

        if(num != 0 && mUnreadCall != num){

            JSONObject callJson = new JSONObject();

            try {

                callJson.put("unreadcall",num);

                mMiFiDataServer.transferWriteQueue(new MiFiBaseBean(MiFiDataServer.STATUS_BAR_NOTIFICATION,callJson));

                mUnreadCall = num;

            } catch (JSONException e) {

                e.printStackTrace();

            }

        }

    }

};

mUnreadCallChangeObserver作为ContentObserver的对象主要实现了一个onChange,构造时传入了一个hanlder方法其实就是观察的内容发生变化时会被触发调用,但是handler的作用被没有体现出来,我们再看ContentObserver类的方法dispatchChange

/**

 * Dispatches a change notification to the observer. Includes the changed

 * content Uri when available and also the user whose content changed.

 * <p>

 * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,

 * then a call to the {@link #onChange} method is posted to the handler's message queue.

 * Otherwise, the {@link #onChange} method is invoked immediately on this thread.

 * </p>

 *

 * @param selfChange True if this is a self-change notification.

 * @param uri The Uri of the changed content, or null if unknown.

 * @param userId The user whose content changed.

 */  

private void dispatchChange(boolean selfChange, Uri uri, int userId) {  

    if (mHandler == null) {  

        onChange(selfChange, uri, userId);  

    } else {  

        mHandler.post(new NotificationRunnable(selfChange, uri, userId));  

    }  

}

如果传入的handler是null,则会调用父类自身的onChange,反之就会通过NotificationRunnable调用到mUnreadCallChangeObserver的onChange方法,而dispatchChange是在内部类Transport 的onChange方法中完成

private static final class Transport extends IContentObserver.Stub {  

    private ContentObserver mContentObserver;  

    public Transport(ContentObserver contentObserver) {  

        mContentObserver = contentObserver;  

    }  

    @Override  

    public void onChange(boolean selfChange, Uri uri, int userId) {  

        ContentObserver contentObserver = mContentObserver;  

        if (contentObserver != null) {  

            contentObserver.dispatchChange(selfChange, uri, userId);  

        }  

    }  

    public void releaseContentObserver() {  

        mContentObserver = null;  

    }  

}

分析到这里,发现接截止在Transport.onChange

注册流程分析:

mUnreadCallChangeObserver的注册

mContext.getContentResolver().registerContentObserver(

            CallLog.Calls.CONTENT_URI, true, mUnreadCallChangeObserver);

接着进入文件ContentResolver.java的registerContentObserver

/**

  • Register an observer class that gets callbacks when data identified by a

  • given content URI changes.

    *

  • @param uri The URI to watch for changes. This can be a specific row URI, or a base URI

  • for a whole class of content.

  • @param notifyForDescendents If true changes to URIs beginning with uri

  • will also cause notifications to be sent. If false only changes to the exact URI

  • specified by uri will cause notifications to be sent. If true, any URI values

  • at or below the specified URI will also trigger a match.

  • @param observer The object that receives callbacks when changes occur.

  • @see #unregisterContentObserver

    */

public final void registerContentObserver(Uri uri, boolean notifyForDescendents,

    ContentObserver observer)  {  

registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());  

}

/* @hide - designated user version /

public final void registerContentObserver(Uri uri, boolean notifyForDescendents,

    ContentObserver observer, int userHandle)  {  

try {  

    getContentService().registerContentObserver(uri, notifyForDescendents,  

            observer.getContentObserver(), userHandle);  

} catch (RemoteException e) {  

}  

}

getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver(), userHandle); 会进入ContentService.registerContentObserve中

public void registerContentObserver(Uri uri, boolean notifyForDescendants,  

            IContentObserver observer, int userHandle) {  

    if (observer == null || uri == null) {  

        throw new IllegalArgumentException("You must pass a valid uri and observer");  

    }  

    enforceCrossUserPermission(userHandle,   "no permission to observe other users' provider view");  

    if (userHandle < 0) {  

        if (userHandle == UserHandle.USER_CURRENT) {  

            userHandle = ActivityManager.getCurrentUser();  

        } else if (userHandle != UserHandle.USER_ALL) {  

            throw new InvalidParameterException("Bad user handle for registerContentObserver: "  

                    + userHandle);  

        }  

    }  

    synchronized (mRootNode) {  

        mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,  

                Binder.getCallingUid(), Binder.getCallingPid(), userHandle);  

        if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +  

                " with notifyForDescendants " + notifyForDescendants);  

    }  

}

其中observer就是mUnreadCallChangeObserver.getContentObserver,如下

/**

  • Gets access to the binder transport object. Not for public consumption.

    *

  • {@hide}

    */

public IContentObserver getContentObserver() {

synchronized (mLock) {  

    if (mTransport == null) {  

        mTransport = new Transport(this);  

    }  

    return mTransport;  

}  

}

ContentService.registerContentObserver传入的observer也即是一个Transport,然后添加到mRootNode中

public void addObserverLocked(Uri uri, IContentObserver observer,  

        boolean notifyForDescendants, Object observersLock,  

        int uid, int pid, int userHandle) {  

    addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,  

            uid, pid, userHandle);  

}  



private void addObserverLocked(Uri uri, int index, IContentObserver observer,  

        boolean notifyForDescendants, Object observersLock,  

        int uid, int pid, int userHandle) {  

    // If this is the leaf node add the observer  

    if (index == countUriSegments(uri)) {  

        mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,  

                uid, pid, userHandle));  

        return;  

    }  

    // Look to see if the proper child already exists  

    String segment = getUriSegment(uri, index);  

    if (segment == null) {  

        throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");  

    }  

    int N = mChildren.size();  

    for (int i = 0; i < N; i++) {  

        ObserverNode node = mChildren.get(i);  

        if (node.mName.equals(segment)) {  

            node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,  

                    observersLock, uid, pid, userHandle);  

            return;  

        }  

    }  



    // No child found, create one  

    ObserverNode node = new ObserverNode(segment);  

    mChildren.add(node);  

    node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,  

            observersLock, uid, pid, userHandle);  

}

在这个过程中,新增的内容观察者全部添加ContentService.mObservers链表中,等待触发。

触发流程:

上面已经分析了,内容观察者的继承,注册,触发则有内容提供的源头来发起,也有ContentProvider来触发。通常数据变化发生在insert,delete,update三个操作中。

ContentProvider在完成insert,delete,update之后就会调用getContext().getContentResolver().notifyChange(url, null)来通知内容发生变化,至此整个注册,触发形成闭环。

ContentService.notifyChange触发函数如下:

/**

 * Notify observers of a particular user's view of the provider.

 * @param userHandle the user whose view of the provider is to be notified.  May be

 *     the calling user without requiring any permission, otherwise the caller needs to

 *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and

 *     USER_CURRENT are properly interpreted; no other pseudousers are allowed.

 */  

@Override  

public void notifyChange(Uri uri, IContentObserver observer,  

        boolean observerWantsSelfNotifications, boolean syncToNetwork,  

        int userHandle) {  

    if (Log.isLoggable(TAG, Log.VERBOSE)) {  

        Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle  

                + " from observer " + observer + ", syncToNetwork " + syncToNetwork);  

    }  



    // Notify for any user other than the caller's own requires permission.  

    final int callingUserHandle = UserHandle.getCallingUserId();  

    if (userHandle != callingUserHandle) {  

        mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,  

                "no permission to notify other users");  

    }  



    // We passed the permission check; resolve pseudouser targets as appropriate  

    if (userHandle < 0) {  

        if (userHandle == UserHandle.USER_CURRENT) {  

            userHandle = ActivityManager.getCurrentUser();  

        } else if (userHandle != UserHandle.USER_ALL) {  

            throw new InvalidParameterException("Bad user handle for notifyChange: "  

                    + userHandle);  

        }  

    }  



    final int uid = Binder.getCallingUid();  

    // This makes it so that future permission checks will be in the context of this  

    // process rather than the caller's process. We will restore this before returning.  

    long identityToken = clearCallingIdentity();  

    try {  

        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();  

        synchronized (mRootNode) {  

            mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,  

                    userHandle, calls);  

        }  

        final int numCalls = calls.size();  

        for (int i=0; i<numCalls; i++) {  

            ObserverCall oc = calls.get(i);  

            try {  

                oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);  

                if (Log.isLoggable(TAG, Log.VERBOSE)) {  

                    Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);  

                }  

            } catch (RemoteException ex) {  

                synchronized (mRootNode) {  

                    Log.w(TAG, "Found dead observer, removing");  

                    IBinder binder = oc.mObserver.asBinder();  

                    final ArrayList<ObserverNode.ObserverEntry> list  

                            = oc.mNode.mObservers;  

                    int numList = list.size();  

                    for (int j=0; j<numList; j++) {  

                        ObserverNode.ObserverEntry oe = list.get(j);  

                        if (oe.observer.asBinder() == binder) {  

                            list.remove(j);  

                            j--;  

                            numList--;  

                        }  

                    }  

                }  

            }  

        }  

        if (syncToNetwork) {  

            SyncManager syncManager = getSyncManager();  

            if (syncManager != null) {  

                syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,  

                        uri.getAuthority());  

            }  

        }  

    } finally {  

        restoreCallingIdentity(identityToken);  

    }  

}

从观察者列表中获取内容观察者(Transport), 然后调用onChange.

相关类图:
这里写图片描述
注册流程图:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值