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

Android内容提供者(ContentProvider)浅析(一)

2014-06-14 12:15 369 查看
ContentProvider是Android系统四大基本组件中涉及到数据共享的重要角色。本文将对它的一些知识做一些简介来引导大家更好的了解这个组件。

下面将从三个方面分析:1、ContentProvider的加载;2、ContentProvider的调用;3、内容监听机制

1、来看看ContentProvider的加载过程,这个组件必须要在manifest文件中注册,这是有原因的,因为应用程序在安装过程中,这个组件的信息就应该被记录下来,以便在应用进程启动时就能直接根据组件信息来创建实例。

这个过程又跟系统的四大关键东西的功能,ActivityManagerService,PackageManagerService,ActivityThread和ApplicationThread。它们的关系相信大家都有一定的了解,这里就不阐述了。

下面从一个应用进程被创建说起。

在ActivityManagerService中,做一些诸如启动界面啊,广播啊,启动服务啊等等需要开始一个新的进程时就会执行到其中的startProcessLocked方法。有一行关键代码

</pre><pre name="code" class="html">Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, null, null);


意思就是说启动一个新进程,并且这个进程的入口是ActivityThread,那么其实对于应用程序来说ActivityThread.main才是它的入口,而并不是我们常说的组件之类的。

继续看main方法:

public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}


这里面建立了主线程的handler和looper当然还有消息队列了,建立起了消息循环机制,所有的主线程操作全部都是在这里进行的。继续看attach操作

private void attach(boolean system) {
if (!system) {
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
}
}


又到ActivityManagerService里面去了,接下来就是一系列的方法调用了,还是长话短说吧,几经波折之后到了ApplicationThread的以下方法中

public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode,
boolean persistent, Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) {
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
......
//将app的provider信息传到ActivityThread的H中处理
queueOrSendMessage(H.BIND_APPLICATION, data);
}
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
private void handleBindApplication(AppBindData data) {
//前面一堆
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
//后面还有Application的OnCreate等操作。
}


关于ContentProvider的重点来了,installContentProviders(app, providers);顾名思义这个里面就把Provider安装到系统中了,这其中包括了创建和注册两步,创建是一个在本进程内创建provider实例并保存,注册其实就是将这个provider在activitymanagerservice保存的过程。来看看具体的代码实现

private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
//创建provider实例
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
//将此记录保存到ActivityManagerService中
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
......
if (holder == null || holder.provider == null) {
try {
final java.lang.ClassLoader cl = c.getClassLoader();
//这里就new出了一个ContentProvider的实例
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}                // XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
}
} else {
            provider = holder.provider;
            if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                    + info.name);
          }
......
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
provider = pr.mProvider;
} else {
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
//上面这个方法中将provider的信息保存在了mProviderMap中。
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
}
}
}
}
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
for (String auth : auths) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord existing = mProviderMap.get(key);
if (existing != null) {
} else {
mProviderMap.put(key, pcr);
}
}
return pcr;
}


看到上面这里,可能大家都会有疑问,为什么这里有三个map来保存provider信息呢?这三个有什么区别什么时候使用这个目前还看不出来,后面的分析可能会看到一些端倪。我们下文将继续分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: