ContentObserver注册和触发流程
获取ContentResolver
mContext.getContentResolver()
Context是一个抽象类,他的实现类之一是ContextImpl,分析ContextImpl源码可以看到:
//android.app.ContextImpl
public ContentResolver getContentResolver() {
return mContentResolver;
}
mContentResolver声明如下:
private final ApplicationContentResolver mContentResolver;
注册阶段
mContext.getContentResolver().registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer)
通过context获取到ContentResolver后,我们知道他是一个ApplicationContentResolver的实例对象,分析ApplicationContentResolver源码,并没有找到registerContentObserver方法,进入他的父类ContentResolver。
registerContentObserver的实现如下:
//android.content.ContentResolver
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer, @UserIdInt int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
getContentService返回的是ContentService的Binder对象,分析ContentService源码:
//com.android.server.content.ContentService
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer, int userHandle, int targetSdkVersion) {
//权限检查等操作,忽略...
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的实例,ObserverNode是ContentService的静态内部类。
ObserverNode内部有ArrayList<ObserverNode>,ArrayList<ObserverEntry>。对于Observer是用树来存储的,可以看作左节点存储的是Children,右节点存储Observer。
举个栗子:content://authority/path1/path2 , authority是path1父节点,path1是path2父节点,即path1左节点存储的path2节点,右节点存储的自己的observer。
//ContentService$ObserverNode
//就是在Observer树上插入节点。用递归实现的(╯°□°)╯︵ ┻━┻
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, uri));
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);
}
( •̀ ω •́ )y注册过程终于说完了。
数据修改
当在自定义ContentProvider里修改数据库后,需要显示调用ContentResolver.notifyChange以达到通知Observer的目的,否则该URI上注册的Observer将不会收到数据改变的通知。
notifyChange阶段
ContentResolver.notifyChange方法最终会进入ContentService.notifyChange,由ContentService分发change事件。
//com.android.server.content.ContentService$ObserverNode
public void notifyChange(Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userId,
int targetSdkVersion, String callingPackage) {
//...忽略亿点点
//收集所有需要通知的observer
synchronized (mRootNode) {
final int segmentCount = ObserverNode.countUriSegments(uri);
mRootNode.collectObserversLocked(uri, segmentCount, 0, observer,
observerWantsSelfNotifications, flags, resolvedUserId, collector);
}
}
final long token = clearCallingIdentity();
try {
// 通知所有Observer
collector.dispatch();
//...忽略亿点点
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
//com.android.server.content.ContentService$ObserverNode
//Observer树上查找所有需要通知的Observer,结果存储在collector里。又是递归(╯°□°)╯︵ ┻━┻
public void collectObserversLocked(Uri uri, int segmentCount, int index,
IContentObserver observer, boolean observerWantsSelfNotifications, int flags,
int targetUserHandle, ObserverCollector collector) {
String segment = null;
if (index >= segmentCount) {
// This is the leaf node, notify all observers
if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
collectMyObserversLocked(uri, true, observer, observerWantsSelfNotifications,
flags, targetUserHandle, collector);
} 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(uri, false, observer, observerWantsSelfNotifications,
flags, targetUserHandle, collector);
}
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, segmentCount, index + 1, observer,
observerWantsSelfNotifications, flags, targetUserHandle, collector);
if (segment != null) {
break;
}
}
}
}
大概写了下ContentObserver注册和触发的时机,中间省略了很多底层的东西,我也不是很懂。
SettingsProvider分析
这里分析下SettingsProvider的源码,分析Settings.Global.putString写入自定义字段的过程。
直接上代码:
//android.provider.Settings.Global
public boolean putStringForUser(ContentResolver cr, String name, String value,
String tag, boolean makeDefault, final int userHandle,
boolean overrideableByRestore) {
try {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(CALL_METHOD_USER_KEY, userHandle);
if (tag != null) {
arg.putString(CALL_METHOD_TAG_KEY, tag);
}
if (makeDefault) {
arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
if (overrideableByRestore) {
arg.putBoolean(CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
//mCallSetCommand = CALL_METHOD_PUT_GLOBAL
cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
}
return true;
}
中间关于binder通信的部分就省略了,我自己也不是很明白。(┬┬﹏┬┬)
//com.android.providers.settings.SettingsProvider
public Bundle call(String method, String name, Bundle args) {
//取出CALL_METHOD_USER_KEY的值
final int requestingUserId = getRequestingUserId(args);
switch (method) {
//...省略亿点点
case Settings.CALL_METHOD_PUT_GLOBAL: {
//取出VALUE的值
String value = getSettingValue(args);
//取出CALL_METHOD_TAG_KEY的值
String tag = getSettingTag(args);
//取出CALL_METHOD_MAKE_DEFAULT_KEY的值
final boolean makeDefault = getSettingMakeDefault(args);
//取出CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY的值
final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false,
overrideableByRestore);
break;
}
//...省略亿点点
}
}
跟进到insertGlobalSetting,再进一步到mutateGlobalSetting,在该方法内进入MUTATION_OPERATION_INSERT这个分支。
//...
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
getCallingPackage(), forceNotify,
CRITICAL_GLOBAL_SETTINGS, overrideableByRestore);
}
//...
public boolean insertSettingLocked(int type, int userId, String name, String value,
String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName,
boolean forceNotify, Set<String> criticalSettings, boolean overrideableByRestore) {
//...
final int key = makeKey(type, userId);
boolean success = false;
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState != null) {
//数据插入在这里。这里返回true会触发对应的Observer
success = settingsState.insertSettingLocked(name, value,
tag, makeDefault, forceNonSystemPackage, packageName, overrideableByRestore);
}
//...
if (forceNotify || success) {
//数据改变后调用notify方法通知observer
notifyForSettingsChange(key, name);
}
return success;
}
public boolean insertSettingLocked(String name, String value, String tag,
boolean makeDefault, boolean forceNonSystemPackage, String packageName,
boolean overrideableByRestore) {
if (TextUtils.isEmpty(name)) {
return false;
}
Setting oldState = mSettings.get(name);
String oldValue = (oldState != null) ? oldState.value : null;
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
Setting newState;
if (oldState != null) {
//值更新操作。天真的我以为Settings.Global.putString只会更新value。真的是naive ಠ_ಠ
if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage,
overrideableByRestore)) {
return false;
}
newState = oldState;
}
//...
return true;
}
private boolean update(String value, boolean setDefault, String packageName, String tag,
boolean forceNonSystemPackage, boolean overrideableByRestore,
boolean resetToDefault) {
//...
//这几个属性都没有改变的情况下才认为Setting的值没有改变
// Is something gonna change?
if (Objects.equals(value, this.value)
&& Objects.equals(defaultValue, this.defaultValue)
&& Objects.equals(packageName, this.packageName)
&& Objects.equals(tag, this.tag)
&& defaultFromSystem == this.defaultFromSystem
&& isPreserved == this.isValuePreservedInRestore) {
return false;
}
return true;
}
不同进程即使对同一个Setting写入相同的值,也会改变Setting,触发Observer。
(❁´◡`❁)菜鸟一个,记录下学习过程。
如果文中有错误,欢迎大家指正。
本文分析了ContentObserver在Android中的注册和触发流程,从获取ContentResolver开始,详细讲解了注册阶段,数据修改后的notifyChange过程,以及SettingsProvider的源码分析,揭示了不同进程中对同一Setting的修改如何触发Observer。
2755

被折叠的 条评论
为什么被折叠?



