android 中的 ContentObserver (二)

文章出处:http://blog.csdn.net/shift_wwx/article/details/48782367

请转载的朋友标明出处~~


前一篇博文(android 中的 ContentObserver (一))中利用最近做的项目,简单的说明了一下 ContentObserver 操作过程,这一篇详细的说一下过程。

总结版本基于4.4


android 中的 ContentObserver (一) 中,提到如果一个db 发生了变化,用户需要最快的知晓。可以做个监听器一直查询db的变化状态,这里需要更正一下,这个不是个好方法,也最好不要想,对于数据表小一点的话,还是可以考虑,可是对于大型的数据表或者字段很多的情况下,这个监听器是没办法做的。

所以,剩下有两种选择,一是选择ContentObserver,另一个选择是广播。

对于两者的区别,大概可以列出下面几点:

一、前者是通过URI来把通知的发送者和接收者关联在一起的,而后者是通过Intent来关联的

二、前者的通知注册中心是由ContentService服务来扮演的,而后者是由ActivityManagerService服务来扮演的

三、前者负责接收数据更新通知的类必须要继承ContentObserver类,而后者要继承BroadcastReceiver类。

从上面这些区别看,两者完全可以做成一个,目前也就是实现的地方不一样而已,其实之所以会有这些区别,主要是因为第四点。

四、Content Proivder组件的数据共享功能本身就是建立在URI的基础之上的,因此专门针对URI来设计另外一套通知机制会更实用和方便,而Android系统的广播机制是一种更加通用的事件通知机制,它的适用范围会更广泛一些。

当然,如果不愿意用 ContentObserver,用广播也是可以,可以将uri 以 param 的形式传递上来。


接下来,根据 source code 来解释一下整个 ContentObserver 的过程

1、注册

android 中的 ContentObserver (一) 中在Channel list 更新的时候需要通知上层,于是在上面注册了一个 ContentObserver:

mContext.getContentResolver().registerContentObserver(Channels.CONTENT_URI, true, mChannelObserver);
其中的三个参数在 android 中的 ContentObserver (一) 中也解释过,这里我们结合 Source code来详细看一下。

看一下 ContentResolver 中的registerContentObserver:frameworks/base/core/java/android/content/ContentResolver.java

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 {
            for (int i = 0; i < 10; i++) {
                IContentService contentService = getContentService();
                if (contentService == null) {
                    //wait for ContentService to be ready
                    SystemClock.sleep(100);
                    continue;
                }
                contentService.registerContentObserver(uri, notifyForDescendents,
                        observer.getContentObserver(), userHandle);
                break;
            }
        } catch (RemoteException e) {
        }
    }
1) getContentServices()

    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;
    }
sContentService 是一个静态成员变量,在sContentService 为null 的时候,会获得前面已经启动起来了的ContentService服务的远程接口,然后把它保存在sContentService变量中。这样,当下次ContentResolver类的getContentService函数再次被调用时,就可以直接把这个ContentService远程接口返回给调用者了。
2)先来看contentService.registerContentObserver中的第三个参数

observer.getContentObserver()

    public IContentObserver getContentObserver() {
        synchronized (mLock) {
            if (mTransport == null) {
                mTransport = new Transport(this);
            }
            return mTransport;
        }
    }
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;
    }
}

ContentObserver类的getContentObserver函数返回的是一个成员变量mTransport,它的类型为ContentObserver的内部类Transport。从Transport类的定义我们可以知道,它有一个成员变量mContentObserver,用来保存与对应的ContentObserver对象。同时我们还可以看出,ContentObserver类的成员变量mTransport是一个Binder对象,它是要传递给ContentService服务的,以便当ContentObserver所监控的数据发生变化时,ContentService服务可以通过这个Binder对象通知相应的ContentObserver它监控的数据发生变化了。

3)contentService.registerContentObserver

@Override
    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);
        }
    }
  它调用了ContentService类的成员变量mRootNode的addObserverLocked函数来注册这个ContentObserver对象observer。成员变量mRootNode的类型为ContentService在内部定义的一个类ObserverNode。
4)mRootNode.addObserverLocked
// Invariant:  userHandle is either a hard user number or is USER_ALL
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);
}
从code 上看,可以分为两部分:

一是 mObservers

private ArrayList mObservers = new ArrayList();
private class ObserverEntry implements IBinder.DeathRecipient {
            public final IContentObserver observer;
            public final int uid;
            public final int pid;
            public final boolean notifyForDescendants;
            private final int userHandle;
            private final Object observersLock;

            public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
                    int _uid, int _pid, int _userHandle) {
                this.observersLock = observersLock;
                observer = o;
                uid = _uid;
                pid = _pid;
                userHandle = _userHandle;
                notifyForDescendants = n;
                try {
                    observer.asBinder().linkToDeath(this, 0);
                } catch (RemoteException e) {
                    binderDied();
                }
            }

            public void binderDied() {
                synchronized (observersLock) {
                    removeObserverLocked(observer);
                }
            }

            public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
                    String name, String prefix, SparseIntArray pidCounts) {
                pidCounts.put(pid, pidCounts.get(pid)+1);
                pw.print(prefix); pw.print(name); pw.print(": pid=");
                        pw.print(pid); pw.print(" uid=");
                        pw.print(uid); pw.print(" user=");
                        pw.print(userHandle); pw.print(" target=");
                        pw.println(Integer.toHexString(System.identityHashCode(
                                observer != null ? observer.asBinder() : null)));
            }
        }

从code 中可以看到 mObservers 这里添加了所有的 ContentObserver 的远程接口。

二是mChildren

private ArrayList mChildren = new ArrayList();
这里存放的是 uri 所有节点。

整理可以知道,如果uri 是content://android.media.tv/channel/1,那么 ObserverNode就可以形成这样的树形:

mRootNode("")
  -- ObserverNode("android.media.tv")
     -- ObserverNode("channel")
         -- ObserverNode("1")
             -- ObserverEntry("observer") // “1” 里面的mObservers size 为1
         -- ObserverEntry()
     -- ObserverEntry()
  -- ObserverEntry()
具体为什么需要在下面继续说明。
注意:这里是通过mRootNode 来做 addObserverLocked() 操作的,里面 mChildren size 是3,mChildren 中每个成员都是ObserverNode 类型,可是这些成员里面
mObservers 却是只有在 index == countUriSegments(uri) 条件成立的时候,那个成员中的mObservers 才会有存在的意义。最终只有在ObserverNode("1")中才是真正注册 observer的地方,即只有ObserverNode("1") 中的 mObservers 才不为 0。

至此,注册的工作就完成了。

2、notifyChange
android 中的 ContentObserver (一) 中在db 变化的时候,会调用notifyChange来发出数据更新的消息。source code 中参数channelUri 是content://android.media.tv/channel
我们加一层,假如这个uri 是content://android.media.tv/channel/1,也就是id 是1发生更新的时候,发出这样的消息。

1)getContext().getContentResolver().notifyChange(uri, null);

public void notifyChange(Uri uri, ContentObserver observer) {
    notifyChange(uri, observer, true /* sync to network */);
}

public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
    notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
}

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) {
    }
}
最终会调用getContentService().notifyChange,getContentService前面介绍过,这里不做过多说明。

2)ContentService.notifyChange

public void notifyChange(Uri uri, IContentObserver observer,
        boolean observerWantsSelfNotifications, boolean syncToNetwork) {
    notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
            UserHandle.getCallingUserId());
}
@Override
public void notifyChange(Uri uri, IContentObserver observer,
        boolean observerWantsSelfNotifications, boolean syncToNetwork,
        int userHandle) {
    ......

    try {
        ArrayList calls = new ArrayList();
        synchronized (mRootNode) {
            mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
                    userHandle, calls);
        }
        final int numCalls = calls.size();
        for (int i=0; i list
                            = oc.mNode.mObservers;
                    int numList = list.size();
                    for (int j=0; j

这个函数主要做了两件事情,第一件事情是调用ContentService的成员变量mRootNode的collectObserverLocked函数来收集那些注册了监控"content://android.media.tv/channel/1"这个URI的ContentObserver,第二件事情是分别调用了这些ContentObserver的onChange函数来通知它们监控的数据发生变化了。

3)ObserverNode.collectObserversLocked()

public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
        boolean observerWantsSelfNotifications, int targetUserHandle,
        ArrayList calls) {
    String segment = null;
    int segmentCount = countUriSegments(uri);
    if (index >= segmentCount) {
        // This is the leaf node, notify all observers
        collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
                targetUserHandle, calls);
    } else if (index < segmentCount){
        segment = getUriSegment(uri, index);
        // Notify any observers at this level who are interested in descendants
        collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
                targetUserHandle, calls);
    }

    int N = mChildren.size();
    for (int i = 0; i < N; i++) {
        ObserverNode node = mChildren.get(i);
        if (segment == null || node.mName.equals(segment)) {
            // We found the child,
            node.collectObserversLocked(uri, index + 1,
                    observer, observerWantsSelfNotifications, targetUserHandle, calls);
            if (segment != null) {
                break;
            }
        }
    }
}

第一次index 为0,而segmentCount 的值为3,所以调用的是:

segment = getUriSegment(uri, index);
// Notify any observers at this level who are interested in descendants
collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
        targetUserHandle, calls);

第一次的时候segment 是 android.media.tv,然后调用 collectMyObserversLocked(),但是之前 registerContentObserver 的时候解释过mRootNode 中的mObservers size 是为0,所以,没有搜集到之前注册的 observer。

第二次的时候segment 是 channel,index 的值变成了 1, 然后继续调用的是:

segment = getUriSegment(uri, index);
// Notify any observers at this level who are interested in descendants
collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
        targetUserHandle, calls);
同样,这个时候 ObserverNode 为 “android.media.tv”,里面的 mObservers size 也是为 0,所以也没有搜集到。

第三次的时候segment 是 1,index 的值变成了 2, 然后继续调用的是:

segment = getUriSegment(uri, index);
// Notify any observers at this level who are interested in descendants
collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
        targetUserHandle, calls);
同样,这个时候ObserverNode 为 “channel”,里面的 mObservers size 也是为 0,所以依然没有搜集到。code 继续走的时候,node.collectObserversLocked() 这个时候的node 已经变成了 ObserverNode 为 “1”,这个时候index 变成了 3,所以调用的是:

collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
    targetUserHandle, calls);

而它里面的 mObservers 的size 为 1,。看以下的代码,这个时候 for 循环可以执行了,最终调用到了calls.add(),至此 observer 才真正搜集到。

注意:如果上面注册的时候 uri 是 content://android.media.tv/channel 那么这里的 count 是3,而在index 是2的时候就可以找到 observer,所以notifyForDescendants 必须要为true,即 注册函数的第二个参数必须要为true。

private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
        boolean observerWantsSelfNotifications, int targetUserHandle,
        ArrayList calls) {
    int N = mObservers.size();
    IBinder observerBinder = observer == null ? null : observer.asBinder();
    for (int i = 0; i < N; i++) {
        ObserverEntry entry = mObservers.get(i);

        // Don't notify the observer if it sent the notification and isn't interested
        // in self notifications
        boolean selfChange = (entry.observer.asBinder() == observerBinder);
        if (selfChange && !observerWantsSelfNotifications) {
            continue;
        }

        // Does this observer match the target user?
        if (targetUserHandle == UserHandle.USER_ALL
                || entry.userHandle == UserHandle.USER_ALL
                || targetUserHandle == entry.userHandle) {
            // Make sure the observer is interested in the notification
            if (leaf || (!leaf && entry.notifyForDescendants)) {
                calls.add(new ObserverCall(this, entry.observer, selfChange));
            }
        }
    }
}

至此第 2)步中:

ArrayList calls = new ArrayList();
calls 就有了。

注意:如果在别的地方在注册一个 uri(例如是 content://android.media.tv/param),同样的在 mRootNode 下的ObserverNode(""android.media.tv) 下会多一个 ObserverNode("param"),跟ObserverNode("channel") 一样,下面的就一样了。

4)接着第2)步,最后会调用 onChange

for (int i=0; i
这里的mObserver 就是IContentObserver, 而IContentObserver 就是之前在register 的时候observer.getContentObserver() 传进来的。
public abstract class ContentObserver {
    ......
    private static final class Transport extends IContentObserver.Stub {
        ContentObserver mContentObserver;
        ......

        public void onChange(boolean selfChange) {
	    ContentObserver contentObserver = mContentObserver;
	    if (contentObserver != null) {
		contentObserver.dispatchChange(selfChange);
	    }
	}
            ......
	}
	......
}
    @Deprecated
    public final void dispatchChange(boolean selfChange) {
        dispatchChange(selfChange, null);
    }
    public final void dispatchChange(boolean selfChange, Uri uri) {
        dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
    }
    private void dispatchChange(boolean selfChange, Uri uri, int userId) {
        if (mHandler == null) {
            onChange(selfChange, uri, userId);
        } else {
            mHandler.post(new NotificationRunnable(selfChange, uri, userId));
        }
    }
如果mHandler 为null,就直接调用 onChange(),如果不为空,就通过 NotificationRunnable 来run;

    private final class NotificationRunnable implements Runnable {
        private final boolean mSelfChange;
        private final Uri mUri;
        private final int mUserId;

        public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
            mSelfChange = selfChange;
            mUri = uri;
            mUserId = userId;
        }

        @Override
        public void run() {
            ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
        }
    }
相当于开了一个线程来处理onChange。

5)调用UI 的onChange

    private final class ChannelObserver extends ContentObserver {

        public ChannelObserver() {
            super(new Handler());
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            updateChannelList();
        }

        @Override
        public IContentObserver releaseContentObserver() {
            // TODO Auto-generated method stub
            return super.releaseContentObserver();
        }

    }


至此,ContentObsrver 或说 Content Provider 的共享数据更新通知机制就分析完了。关于ContentProvider 可以看一下: Android基础总结之八:ContentProvider




你可能感兴趣的:(android,----,db)