简介
ContentProvider 是一种内容共享型组件,其主要职责是向其他组件以及其他应用提供数据。当 ContentProvider 所在的进程启动时,ContentProvider 会同时启动并被发布到 AMS 中。
注意:ContentProvider 的 onCreate 要先于 Application 的 onCreate 执行
是否是单例
一般来说,ContentProvider 都应该是单例的,ContentProvider 是否单例取决于注册时的 android:multiprcess 属性,如果该属性为 false ,则是单例的,这也是默认值。当 android:multiprocess 为 true 时为多例,这时候在每个调用者的进程中都存在一个 ContentProvider 对象。
发布过程
应用进程 & 系统进程
当 ContentProvider 所在进程启动时,在 ActivityThread 的 main 函数中,调用 attach 方法,attach 方法中会调用 AMS 的 attachApplication 方法,最终通过 IPC 在 AMS 中调用 ActivityThread 中 ApplicationThread 的 bindApplication 方法,通过消息机制调用 ActivityThread 的 handleBindApplication 方法
handleBindApplication 方法中有如下代码
// 初始化 Application,并在初始化时调用 Application 的 attachBaseContext(Context context) 方法为 Application 附加上 Context,所以在 attachBase 方法中调用 getApplication 方法得到的是空
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
// 加载 ContentProvider,并调用其 onCreate 方法
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers; // prividers 是根据新启动的应用进程的信息,由系统进程在系统启动时注册的 ContentProvider 中筛选出来的,启动 Application 时从系统进程传递过来
if (providers != null) {
installContentProviders(app, providers); // 初始化 ContentProvider,其中会调用 onCreate 方法
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// 调用 Application 的 onCreate 方法,由此可见,ContentProvider 的 onCreate 方法早于 Application 的 onCreate 方法
mInstrumentation.callApplicationOnCreate(app);
installContentProviders 方法中遍历 providers 集合,分别调用 installProvider 方法的到 ContentProviderHolder 对象, installProvider 中使用 ClassLoader 初始化 ContentProvider 对象,然后调用 ContentProvider 的 attachInfo 方法初始化其信息,其中调用了 onCreate 方法。然后根据注册清单中注册的 ContentProvider 的信息,构造 ContentProviderHolder 对象,ContentProviderHolder 是可序列化的 ContentProvider,接着将IcontentProvider 放入已发布的 IContentProvider 的集合, 再将 ContentProviderHolder 对象放入集合中,通过 AMS 的 publishContentProviders 方法远程发布 ContentProviderHolder 集合到系统进程。这就完成了当前应用中 ContentProvider 的发布。
ContentProviderHolder 中还有 IContentProvider 的引用,IContentProvider 继承了 IInterface 接口,可在 Binder 中传输,其子类是 ContentProviderNative 也是抽象类,其实现类为 ContentProvider 中的一个内部类 Transport ,在 Transport 实现的方法中调用了 ContentProvider 中的方法,所以 Transport 为 AIDL 中的 Stub 类,将 Transport 的引用放入 ContentProviderHolder 中,在系统进程可以得到 Transport 的代理 Proxy,在系统进程中通过 IPC 就可以调用 Transport 的方法,从而调用 ContentProvider 的方法。
工作过程
-
在使用 ContentProvider 时,我们会通过 ContentResolver 来进行操作
-
Context 对象的 getContenResolver 方法,返回一个 ApplicationContentResolver 类对象,该类继承自 ContentResolver ,在 ContentImpl 构造方法中通 ApplicationContentResolver 类的构造方法初始化 ApplicationContentResolver 对象。
-
以 query 方法为例,ApplicationContentResolver 的 query 方法,会调用 ContentResolver 的 query 方法,query 方法中调用 acquireProvider 方法来获取 IContentProvider 对象,IContentnProvider 继承了 IInterface 接口,ApplicationContentResolver 在 ContentResolver 中是抽象方法,最终会调用 ApplicationContentResolver 的 acquireProvider 方法,在调用 query 方法时会将 Uri 构造成 String 并以参数的形式传递
-
acquireProvider 方法中,会调用当前应用 ActivityThread 的 acquireProvider 方法来获取能处理当前 Uri 的 IContentProvider 对象,acquireProvider 方法中,会根据要操作的 Uri 来查找是否当前发布的 ContentProvider 中是否有对应的,如果有则直接返回,如果没有则通过进程间通信通知 AMS 的 getContentProvider 方法启动需要的 ContentProvider 所在的进程,进程启动之后 ContentProvider 也会发布,得到对应的 ContentProvider 之后 AMS 会将其返回,acquireProvider 方法中也将得到的 IContentProvider 返回到 ApplicationContentResolver 的 query 方法中。
-
ApplicationContentResolver 的 acquireProvider 方法中得到 IContentProvider 之后,通过 AMS 来访问 ContentProvider ,这里的 IContentProvider 是 AIDL 中的 Proxy,通过 IPC 调用 ContentProvider.Transport 对象的方法,Transport 的 query 方法,调用我们自定义的 ContentProvider 的 query 方法,并将结果返回到 acquireProvider 方法,在返回到客户端调用的 query 方法,完成工作。
网友评论