ContentProvider工作机制

本章分监听机制、通知机制和数据库访问三个部分进行分析。

一、监听机制

在android中,我们可以通过ContentResolver监听数据库的变化,这一节我们来看监听是如何实现的。
我们首先会获取ContentResolver,在ContextImpl中调用getContentResolver()即可,它会返回一个内部类对象,如下:

public ContentResolver getContentResolver() {
        return mContentResolver;
}

    public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
            @NonNull ContentObserver observer) {
        Preconditions.checkNotNull(uri, "uri");
        Preconditions.checkNotNull(observer, "observer");
        registerContentObserver(
                ContentProvider.getUriWithoutUserId(uri),
                notifyForDescendants,
                observer,
                ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
    }

通过调用registerContentObserver进行注册动作,第一个参数为监听的uri,也就是我们需要监听的数据库字段;第二个参数为监听是否需要监听派生的uri还是只严格匹配该uri,在后面通知机制一节中我们再看该变量是如何控制的;第三个为重写的ContentObserver。注意到ContentResolver实际就是通过ContentService这个系统服务来操作的,这里其实容易理解,注册的信息应该交给系统服务来统一管理。接下来看ContentService的registerContentObserver方法:

   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");
        }

        final int uid = Binder.getCallingUid();
        final int pid = Binder.getCallingPid();
        final int callingUserHandle = UserHandle.getCallingUserId();
        // Registering an observer for any user other than the calling user requires uri grant or
        // cross user permission
        if (callingUserHandle != userHandle) {
            if (checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle)
                    != PackageManager.PERMISSION_GRANTED) {
                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,
                    uid, pid, userHandle);
            if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
                    " with notifyForDescendants " + notifyForDescendants);
        }
    }

mRootNode是一个根节点,它是一个ObserverNode对象,从它的初始化看到它的name是空字符串。来到它的addObserverLocked方法:

       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);
        }

第一次传入的index为0,第一个判断是如果传入的uri的segment数量刚好和index一样,才会创建一个新的ObserverEntry放到该ObserverNode对象的容器mObservers中,我们传入的uri segment个数肯定是大于0的。比如:content://com.rhythmjay.providers/item/0的个数就是3。接下来取index为0的segemt,也就是com.rhythmjay.providers,遍历mRootNode的所有子节点,查找子节点中是否有name为com.rhythmjay.providers,有则调用该子节点的addObserverLocked方法且index+1,否则创建一个name为com.rhythmjay.providers的子节点调用其addObserverLocked方法且index+1。
第二次传入的index为1,第一个判断仍然不满足,获取index为1的segment为item。寻找或者创建name为item的子节点,调用其addObserverLocked并且index+1。
第三次传入的index为2,第一个判断仍然不满足,获取index为2的segment为0. 寻找或者创建name为0的子节点,调用其addObserverLocked并且index+1。
第四次传入的index为3,第一个判断满足,直接通过observer新建ObserverNode对象并放入到该子节点的容器mObservers中。
至此,我们可以看到ContentService中实际保存了一颗类似树状的信息,每个叶子节点都根据segment有命名,从根节点到叶子节点保存了一条uri的信息,且每个叶子节点都有保存这条路径uri的监听者observer。

二、通知机制

我们在自定义ContentProvider时,会将一些客户敏感的字段变化通知出去,而这也是通过ContentResolver完成的。首先我们确认好通知的条件,满足条件后我们就可以调用如下方法通知给感兴趣的客户端:
getContext().getContentResolver().notifyChange(CONTENT_URI, null);
这里也会通过ContentService完成通知:

    public void notifyChange(Uri uri, IContentObserver observer,
                             boolean observerWantsSelfNotifications, int flags,
                             int userHandle) {
        ......
        try {
            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
            synchronized (mRootNode) {
                mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
                        flags, 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 (DEBUG) Slog.d(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 ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
                SyncManager syncManager = getSyncManager();
                if (syncManager != null) {
                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
                            uri.getAuthority());
                }
            }
    ......
    }

这里有个flags,通过上述方式通知的话默认为NOTIFY_SYNC_TO_NETWORK,意思就是会通知网络服务器。这里有创建一个ObserverCall的列表calls,它是一个输出参数,接下来就是从mRootNode来搜集所有的observer了。

        public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
                                           boolean observerWantsSelfNotifications, int flags,
                                           int targetUserHandle, ArrayList<ObserverCall> calls) {
            String segment = null;
            int segmentCount = countUriSegments(uri);
            if (index >= segmentCount) {
                // This is the leaf node, notify all observers
                if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
                collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
                        flags, targetUserHandle, calls);
            } else if (index < segmentCount){
                segment = getUriSegment(uri, index);
                if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
                        + segment);
                // Notify any observers at this level who are interested in descendants
                collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
                        flags, targetUserHandle, calls);
            }

            int N = mChildren.size();
            for (int i = 0; i < N; i+
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值