文章出处: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远程接口返回给调用者了。
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。
// 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就可以形成这样的树形:
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();
}
}