您的位置:首页 > 移动开发 > Android开发

android 中的 ContentObserver (二)

2015-09-28 11:20 465 查看
文章出处: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<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();

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<ObserverNode> mChildren = new ArrayList<ObserverNode>();

这里存放的是 uri 所有节点。

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

mRootNode("")

  -- ObserverNode("android.media.tv")

     -- ObserverNode("channel")

         -- ObserverNode("1")

             -- [b][b]ObserverEntry("observer")
// “1” 里面的mObservers size 为1
[/b][/b]

         [b][b]-- ObserverEntry()[/b][/b]
     -- 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<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);
}
}

这个函数主要做了两件事情,第一件事情是调用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<ObserverCall> 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<ObserverCall> 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<ObserverCall> calls = new ArrayList<ObserverCall>();

calls 就有了。

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

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

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

这里的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: