文章出处: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_ALLpublic 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());}
@Overridepublic 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 descendantscollectMyObserversLocked(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 descendantscollectMyObserversLocked(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 descendantscollectMyObserversLocked(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




更多相关文章

  1. Android的MediaPlayer架构介绍
  2. Android源码阅读分析:从Activity开始(一)——启动流程
  3. android:configChanges属性
  4. Android音频流程一(JNI部分)
  5. Android完全退出应用程序
  6. Android通过调用Webservice实现天气预报
  7. Android(安卓)Uevent 分析,从kernel到framework
  8. Android第三方异步网路加载库AsyncHttpClient内部实现缓存策略了
  9. Android(安卓)基础总结:(三)Activity

随机推荐

  1. 如何在android的jni线程中实现回调
  2. Android(安卓)利用addView 动态给Activit
  3. Android(安卓)-- AppWidget 高级篇
  4. TX Android电面问题
  5. Android新手笔记—Android(安卓)Studio的
  6. android 应用程序包文件 (APK)
  7. 页面调用ADB操作Android设备
  8. Android(安卓)adb不是内部或外部命令 问
  9. YUV420图像旋转90算法的优化
  10. Linux手机打电话代码分析