3.数据更新通知的发送过程 在前面这篇文章 Android应用程序组件Content Provider应用实例 介绍的应用程序Acticle中,当调用ArticlesAdapter类的insertArticle往ArticlesProvider中增加一个文章信息条目时:
        
  1. publicclassArticlesAdapter{
  2. ......
  3. publiclonginsertArticle(Articlearticle){
  4. ContentValuesvalues=newContentValues();
  5. values.put(Articles.TITLE,article.getTitle());
  6. values.put(Articles.ABSTRACT,article.getAbstract());
  7. values.put(Articles.URL,article.getUrl());
  8. Uriuri=resolver.insert(Articles.CONTENT_URI,values);
  9. StringitemId=uri.getPathSegments().get(1);
  10. returnInteger.valueOf(itemId).longValue();
  11. }
  12. ......
  13. }
便会进入到应用程序ArticlesProvider中的ArticlesProvider类的insert函数中:
        
  1. publicclassArticlesProviderextendsContentProvider{
  2. ......
  3. @Override
  4. publicUriinsert(Uriuri,ContentValuesvalues){
  5. if(uriMatcher.match(uri)!=Articles.ITEM){
  6. thrownewIllegalArgumentException("ErrorUri:"+uri);
  7. }
  8. SQLiteDatabasedb=dbHelper.getWritableDatabase();
  9. longid=db.insert(DB_TABLE,Articles.ID,values);
  10. if(id<0){
  11. thrownewSQLiteException("Unabletoinsert"+values+"for"+uri);
  12. }
  13. UrinewUri=ContentUris.withAppendedId(uri,id);
  14. resolver.notifyChange(newUri,null);
  15. returnnewUri;
  16. }
  17. ......
  18. }
从上面传来的参数uri的值为"content://shy.luo.providers.articles/item"。假设当这个函数把数据成功增加到SQLite数据库之后,返回来的id值为n,于是通过调用ContentUris.withAppendedId("content://shy.luo.providers.articles/item", n)得到的newUri的值就为"content://shy.luo.providers.articles/item/n"。这时候就会调用下面语句来通知那些注册了监控"content://shy.luo.providers.articles/item/n"这个URI的ContentObserver,它监控的数据发生变化了:
        
  1. resolver.notifyChange(newUri,null);
下面我们就开始分析这个数据变化通知的发送过程,首先来看一下这个过程的时序图,然后再详细分析每一个步骤:

Step 1. ContentResolver.notifyChange
这个函数定义在frameworks/base/core/java/android/content/ContentResolver.java文件中:
        
  1. publicabstractclassContentResolver{
  2. ......
  3. publicvoidnotifyChange(Uriuri,ContentObserverobserver){
  4. notifyChange(uri,observer,true/*synctonetwork*/);
  5. }
  6. publicvoidnotifyChange(Uriuri,ContentObserverobserver,booleansyncToNetwork){
  7. try{
  8. getContentService().notifyChange(
  9. uri,observer==null?null:observer.getContentObserver(),
  10. observer!=null&&observer.deliverSelfNotifications(),syncToNetwork);
  11. }catch(RemoteExceptione){
  12. }
  13. }
  14. ......
  15. }
这里调用了ContentService的远接程口来调用它的notifyChange函数来发送数据更新通知。

Step 2.ContentService.notifyChange 这个函数定义在frameworks/base/core/java/android/content/ContentService.java文件中:
        
  1. publicfinalclassContentServiceextendsIContentService.Stub{
  2. ......
  3. publicvoidnotifyChange(Uriuri,IContentObserverobserver,
  4. booleanobserverWantsSelfNotifications,booleansyncToNetwork){
  5. ......
  6. try{
  7. ArrayList<ObserverCall>calls=newArrayList<ObserverCall>();
  8. synchronized(mRootNode){
  9. mRootNode.collectObserversLocked(uri,0,observer,observerWantsSelfNotifications,
  10. calls);
  11. }
  12. finalintnumCalls=calls.size();
  13. for(inti=0;i<numCalls;i++){
  14. ObserverCalloc=calls.get(i);
  15. try{
  16. oc.mObserver.onChange(oc.mSelfNotify);
  17. ......
  18. }catch(RemoteExceptionex){
  19. ......
  20. }
  21. }
  22. ......
  23. }finally{
  24. ......
  25. }
  26. }
  27. ......
  28. }

这个函数主要做了两件事情,第一件事情是调用ContentService的成员变量mRootNode的collectObserverLocked函数来收集那些注册了监控"content://shy.luo.providers.articles/item/n"这个URI的ContentObserver,第二件事情是分别调用了这些ContentObserver的onChange函数来通知它们监控的数据发生变化了。

Step 3. ObserverNode.collectObserversLocked 这个函数定义在frameworks/base/core/java/android/content/ContentService.java文件中:
        
  1. publicfinalclassContentServiceextendsIContentService.Stub{
  2. ......
  3. publicstaticfinalclassObserverNode{
  4. ......
  5. privatevoidcollectMyObserversLocked(booleanleaf,IContentObserverobserver,
  6. booleanselfNotify,ArrayList<ObserverCall>calls){
  7. intN=mObservers.size();
  8. IBinderobserverBinder=observer==null?null:observer.asBinder();
  9. for(inti=0;i<N;i++){
  10. ObserverEntryentry=mObservers.get(i);
  11. //Don'tnotifytheobserverifitsentthenotificationandisn'tinteresed
  12. //inselfnotifications
  13. if(entry.observer.asBinder()==observerBinder&&!selfNotify){
  14. continue;
  15. }
  16. //Makesuretheobserverisinterestedinthenotification
  17. if(leaf||(!leaf&&entry.notifyForDescendents)){
  18. calls.add(newObserverCall(this,entry.observer,selfNotify));
  19. }
  20. }
  21. }
  22. publicvoidcollectObserversLocked(Uriuri,intindex,IContentObserverobserver,
  23. booleanselfNotify,ArrayList<ObserverCall>calls){
  24. Stringsegment=null;
  25. intsegmentCount=countUriSegments(uri);
  26. if(index>=segmentCount){
  27. //Thisistheleafnode,notifyallobservers
  28. collectMyObserversLocked(true,observer,selfNotify,calls);
  29. }elseif(index<segmentCount){
  30. segment=getUriSegment(uri,index);
  31. //Notifyanyobserversatthislevelwhoareinterestedindescendents
  32. collectMyObserversLocked(false,observer,selfNotify,calls);
  33. }
  34. intN=mChildren.size();
  35. for(inti=0;i<N;i++){
  36. ObserverNodenode=mChildren.get(i);
  37. if(segment==null||node.mName.equals(segment)){
  38. //Wefoundthechild,
  39. node.collectObserversLocked(uri,index+1,observer,selfNotify,calls);
  40. if(segment!=null){
  41. break;
  42. }
  43. }
  44. }
  45. }
  46. }
  47. }

第一次调用collectObserversLocked时,是在mRootNode的这个ObserverNode节点中进行收集ContentObserver的。这时候传进来的uri的值为"content://shy.luo.providers.articles/item/n",index的值为0。调用countUriSegments("content://shy.luo.providers.articles/item/n")函数得到的返回值为3,于是就会调用下面语句:
        
  1. segment=getUriSegment("content://shy.luo.providers.articles/item/n",0);
  2. //Notifyanyobserversatthislevelwhoareinterestedindescendents
  3. collectMyObserversLocked(false,observer,selfNotify,calls);
这里得到的segment为"shy.luo.providers.articles"。在我们这个情景中,假设mRootNode这个节点中没有注册ContentObserver,于是调用collectMyObserversLocked函数就不会收集到ContentObserver。

在接下来的for循环中,在mRootNode的孩子节点列表mChildren中查找名称等于"shy.luo.providers.articles"的OberverNode节点。在上面分析ContentObserver的注册过程时,我们已经往mRootNode的孩子节点列表mChildren中增加了一个名称为"shy.luo.providers.articles"的OberverNode节点,因此,这里会成功找到它,并且调用它的collectObserversLocked函数来继续收集ContentObserver。 第二次进入到collectObserversLocked函数时,是在名称为"shy.luo.providers.articles"的OberverNode节点中收集ContentObserver的。这时候传来的uri值不变,但是index的值为1,于是执行下面语句:
        
  1. segment=getUriSegment("content://shy.luo.providers.articles/item/n",1);
  2. //Notifyanyobserversatthislevelwhoareinterestedindescendents
  3. collectMyObserversLocked(false,observer,selfNotify,calls);

这里得到的segment为"item"。在我们这个情景中,我们没有在名称为"shy.luo.providers.articles"的OberverNode节点中注册有ContentObserver,因此这里调用collectMyObserversLocked函数也不会收集到ContentObserver。

在接下来的for循环中,在名称为"shy.luo.providers.articles"的ObserverNode节点的孩子节点列表mChildren中查找名称等于"item"的OberverNode节点。在上面分析ContentObserver的注册过程时,我们已经往名称为"shy.luo.providers.articles"的ObserverNode节点的孩子节点列表mChildren中增加了一个名称为"item"的OberverNode节点,因此,这里会成功找到它,并且调用它的collectObserversLocked函数来继续收集ContentObserver。 第三次进入到collectObserversLocked函数时,是在名称为"shy.luo.providers.articles"的OberverNode节点的子节点中名称为"item"的ObserverNode节点中收集ContentObserver的。这时候传来的uri值不变,但是index的值为2,于是执行下面语句:
  1. segment=getUriSegment("content://shy.luo.providers.articles/item/n",2);
  2. //Notifyanyobserversatthislevelwhoareinterestedindescendents
  3. collectMyObserversLocked(false,observer,selfNotify,calls);

这里得到的segment为"n"。前面我们已经在名称为"shy.luo.providers.articles"的OberverNode节点的子节点中名称为"item"的ObserverNode节点中注册了一个ContentObserver,即ArticlesObserver,因此这里调用collectMyObserversLocked函数会收集到这个ContentObserver。注意,这次调用collectMyObserversLocked函数时,虽然传进去的参数leaf为false,但是由于我们注册ArticlesObserver时,指定了notifyForDescendents参数为true,因此,这里可以把它收集回来。

在接下来的for循环中,继续在该节点的子节点列表mChildren中查找名称等于"n"的OberverNode节点。在我们这个情景中,不存在这个名称为"n"的子节点了,于是收集ContentObserver的工作就结束了,收集结果是只有一个ContentObserver,即我们在前面注册的ArticlesObserver。 返回到Step2中,调用下面语句来通知相应的ContentObserver,它们监控的数据发生变化了:
  1. for(inti=0;i<numCalls;i++){
  2. ObserverCalloc=calls.get(i);
  3. try{
  4. oc.mObserver.onChange(oc.mSelfNotify);
  5. ......
  6. }catch(RemoteExceptionex){
  7. ......
  8. }
  9. }

前面我们在分析ContentObserver的注册过程的Step3时,介绍到注册到ContentService服务中的ContentObserver是一个在ContentObserver内部定义的一个类Transport的对象的远程接口,于是这里调用这个接口的onChange函数时,就会进入到ContentObserver的内部类Transport的onChange函数中去。

更多相关文章

  1. Android SQLite数据库升级的问题
  2. 使用SharedPreferences存储和读取数据
  3. Android:Content Provider数据共享
  4. android中usb数据通信速率慢问题解决办法
  5. Android sqlite 数据库操作
  6. Android 自定义Listview 如何绑定Sqlite数据库数据
  7. Android的数据存储
  8. Android APN的设置问题 默认“已起用数据” 关闭

随机推荐

  1. Mybatis 配置 自定义缓存 ehcache
  2. C语言复习(二)
  3. ThingJS官方示例(十一):基于数据矢量及贴图u
  4. 用Python实现手机抓包,获取当当图书差评数
  5. Android(安卓)OTA升级包制作脚本详解(四,生
  6. 使用内存NewSQL数据平台来处理实时数据流
  7. 这款可视化工具也太好用了吧
  8. Android上打包jar并在真机上运行
  9. Python数据可视化:浅谈数据分析岗
  10. 11种数据分析方法,别再说你不会了