Android应用程序组件Content Provider的启动过程源代码分析(6)


 Step 17. ActivityThread.installProvider
        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

  1. public final class ActivityThread {   
  2.     ......   
  3.        
  4.     private final IContentProvider installProvider(Context context,   
  5.             IContentProvider provider, ProviderInfo info, boolean noisy) {   
  6.         ContentProvider localProvider = null;   
  7.         if (provider == null) {   
  8.             ......   
  9.    
  10.             Context c = null;   
  11.             ApplicationInfo ai = info.applicationInfo;   
  12.             if (context.getPackageName().equals(ai.packageName)) {   
  13.                 c = context;   
  14.             } else if (mInitialApplication != null &&   
  15.                 mInitialApplication.getPackageName().equals(ai.packageName)) {   
  16.                     c = mInitialApplication;   
  17.             } else {   
  18.                 try {   
  19.                     c = context.createPackageContext(ai.packageName,   
  20.                         Context.CONTEXT_INCLUDE_CODE);   
  21.                 } catch (PackageManager.NameNotFoundException e) {   
  22.                 }   
  23.             }   
  24.    
  25.             ......   
  26.    
  27.             try {   
  28.                 final java.lang.ClassLoader cl = c.getClassLoader();   
  29.                 localProvider = (ContentProvider)cl.   
  30.                     loadClass(info.name).newInstance();   
  31.                 provider = localProvider.getIContentProvider();   
  32.                 ......   
  33.    
  34.                 // XXX Need to create the correct context for this provider.   
  35.                 localProvider.attachInfo(c, info);   
  36.             } catch (java.lang.Exception e) {   
  37.                 ......   
  38.             }   
  39.    
  40.         } else if (localLOGV) {   
  41.             ......   
  42.         }   
  43.    
  44.         synchronized (mProviderMap) {   
  45.             // Cache the pointer for the remote provider.   
  46.             String names[] = PATTERN_SEMICOLON.split(info.authority);   
  47.             for (int i=0; i<names.length; i++) {   
  48.                 ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,   
  49.                     localProvider);   
  50.                 try {   
  51.                     provider.asBinder().linkToDeath(pr, 0);   
  52.                     mProviderMap.put(names[i], pr);   
  53.                 } catch (RemoteException e) {   
  54.                     return null;   
  55.                 }   
  56.             }   
  57.             if (localProvider != null) {   
  58.                 mLocalProviders.put(provider.asBinder(),   
  59.                     new ProviderClientRecord(null, provider, localProvider));   
  60.             }   
  61.         }   
  62.    
  63.         return provider;   
  64.     }   
  65.    
  66.     ......   
  67. }   
  这个函数的作用主要就是在应用程序进程中把相应的Content Provider类加载进来了,在我们这个种情景中,就是要在ArticlesProvider这个应用程序中把ArticlesProvider这个Content Provider类加载到内存中来了:

  1. final java.lang.ClassLoader cl = c.getClassLoader();   
  2. localProvider = (ContentProvider)cl.   
  3.     loadClass(info.name).newInstance();   
    接着通过调用localProvider的getIContentProvider函数来获得一个Binder对象,这个Binder对象返回给installContentProviders函数之后,就会传到ActivityManagerService中去,后续其它应用程序就是通过获得这个Binder对象来和相应的Content Provider进行通信的了。我们先看一下这个函数的实现,然后再回到installProvider函数中继续分析。

 
         Step 18. ContentProvider.getIContentProvider
         这个函数定义在frameworks/base/core/java/android/content/ContentProvider.java文件中:

  1. public abstract class ContentProvider implements ComponentCallbacks {   
  2.     ......   
  3.    
  4.     private Transport mTransport = new Transport();   
  5.    
  6.     ......   
  7.    
  8.     class Transport extends ContentProviderNative {   
  9.         ......   
  10.     }   
  11.    
  12.     public IContentProvider getIContentProvider() {   
  13.         return mTransport;   
  14.     }   
  15.    
  16.     ......   
  17. }   

       从这里我们可以看出,ContentProvider类和Transport类的关系就类似于ActivityThread和ApplicationThread的关系,其它应用程序不是直接调用ContentProvider接口来访问它的数据,而是通过调用它的内部对象mTransport来间接调用ContentProvider的接口,这一点我们在下一篇文章中分析调用Content Provider接口来获取共享数据时将会看到。
        回到前面的installProvider函数中,它接下来调用下面接口来初始化刚刚加载好的Content Provider:
  1. // XXX Need to create the correct context for this provider.  
  2. localProvider.attachInfo(c, info);  
        同样,我们先进入到ContentProvider类的attachInfo函数去看看它的实现,然后再回到installProvider函数来。
 
        Step 19. ContentProvider.attachInfo
        这个函数定义在frameworks/base/core/java/android/content/ContentProvider.java文件中:

  1. public abstract class ContentProvider implements ComponentCallbacks {   
  2.     ......   
  3.    
  4.     public void attachInfo(Context context, ProviderInfo info) {   
  5.         /*  
  6.         * Only allow it to be set once, so after the content service gives  
  7.         * this to us clients can't change it.  
  8.         */   
  9.         if (mContext == null) {   
  10.             mContext = context;   
  11.             mMyUid = Process.myUid();   
  12.             if (info != null) {   
  13.                 setReadPermission(info.readPermission);   
  14.                 setWritePermission(info.writePermission);   
  15.                 setPathPermissions(info.pathPermissions);   
  16.                 mExported = info.exported;   
  17.             }   
  18.             ContentProvider.this.onCreate();   
  19.         }   
  20.     }   
  21.    
  22.     ......   
  23. }   
      这个函数很简单,主要就是根据这个Content Provider的信息info来设置相应的读写权限,然后调用它的子类的onCreate函数来让子类执行一些初始化的工作。在我们这个情景中,这个子类就是ArticlesProvide应用程序中的ArticlesProvider类了。

        Step 20. ArticlesProvider.onCreate
        这个函数定义在前面一篇文章Android应用程序组件Content Provider应用实例介绍的应用程序ArtilcesProvider源代码工程目录下,在文件为packages/experimental/ArticlesProvider/src/shy/luo/providers/articles/ArticlesProvider.java中:
  1. public class ArticlesProvider extends ContentProvider {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public boolean onCreate() {  
  6.         Context context = getContext();  
  7.         resolver = context.getContentResolver();  
  8.         dbHelper = new DBHelper(context, DB_NAME, null, DB_VERSION);  
  9.   
  10.         return true;  
  11.     }  
  12.   
  13.     ......  
  14. }  

        这个函数主要执行一些简单的工作,例如,获得应用程序上下文的ContentResolver接口和创建数据库操作辅助对象,具体可以参考前面一篇文章Android应用程序组件Content Provider应用实例

 
        回到前面Step 17中的installProvider函数中,它接下来就是把这些在本地中加载的Content Provider信息保存下来了,以方便后面查询和使用:
  1. synchronized (mProviderMap) {  
  2.     // Cache the pointer for the remote provider.  
  3.     String names[] = PATTERN_SEMICOLON.split(info.authority);  
  4.     for (int i=0; i<names.length; i++) {  
  5.     ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,  
  6.         localProvider);  
  7.     try {  
  8.         provider.asBinder().linkToDeath(pr, 0);  
  9.         mProviderMap.put(names[i], pr);  
  10.     } catch (RemoteException e) {  
  11.         return null;  
  12.     }  
  13.     }  
  14.     if (localProvider != null) {  
  15.     mLocalProviders.put(provider.asBinder(),  
  16.         new ProviderClientRecord(null, provider, localProvider));  
  17.     }  
  18. }  

        和ActivityMangerService类似,在ActivityThread中,以Content Provider的authority为键值来把这个Content Provider的信息保存在mProviderMap成员变量中,因为一个Content Provider可以对应多个authority,因此这里用一个for循环来处理,同时又以这个Content Provider对应的Binder对象provider来键值来把这个Content Provider的信息保存在mLocalProviders成员变量中,表明这是一个在本地加载的Content Provider。



本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966989,如需转载请自行联系原作者
上一篇:分享22款响应式的 jQuery 图片滑块插件


下一篇:【云周刊】第222期:从遇见到信任 | Apache Dubbo 的毕业之旅