赞
踩
ContentProvider作为四大组件之一,由于业务上用到的地方不多,目前业务是系统界面,属于系统应用,最适合使用ContentProvider来进行少量数据存储,我们业务中涉及到的Settings.system和Settings.Secure等数据库,就是通过ContentProvider来封装、用ContentResolver来访问的
//通过ContentResolver来访问Settings.Secure
final boolean userSetup = 0 != Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE,
0 /*default */,
mCurrentUserId);
//通过ContentResolver来访问Settings.Global
Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HEADS_UP_OFF);
除了上面的用法,平时也很少自己自定义一个ContentProvider。现在来Read the fucking code,稍微深入了解下:
我们知道ContentProvider提供跨进程的数据传输,通过ContentResolver.registerContentObserver()的方式来监听数据变化,一旦ContentProvider中数据改变(也可能是被其他进程修改),就是触发ContentObserver中的回调方法
@Override
public void onChange(boolean selfChange) {
//读取ContentProvider中的值操作
}
那么ContentProvider、ContentResolver、ContentObserver三者之间存在着什么样的联系?
在Context实例化之后,会初始化mContentResolver
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
这个值就是我们getContentResolver()获得的ContentResolver对象。
ContentResolver有下面几个方法:
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
@Nullable String[] selectionArgs) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);//这里获取ContentProvider代理
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
return rowsDeleted;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return -1;
} finally {
releaseProvider(provider);
}
}
看上面注释,发现调用了下面这个抽象方法
protected abstract IContentProvider acquireProvider(Context c, String name);
再去ApplicationContentProvider中查看,最终发现是在ActivityThread中installProvider方法来加载Provider
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。