Android应用程序组件Content Provider的共享数据更新通知机制分析

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Android应用程序组件ContentProvider的共享数据更新通知机制分析在Android系统中,应用程序组件ContentProvider为不同的应用程序实现数据共享提供了基础设施,它主要通过Binder进程间通信机制和匿名共享内存机制来实现的。关于数据共享的另一个话题便是数据更新通知机制了,即如果一个应用程序对共享数据做了修改,它应该如何通知其它正在使用这些共享数据的应用程序呢?本文将分析ContentProvider的共享数据更新通知机制,为读者解答这个问题。Android应用程序组件ContentProvider中的数据更新通知机制和Android系统中的广播(Broadcast)通知机制的实现思路是相似的。在Android的广播机制中,首先是接收者对自己感兴趣的广播进行注册,接着当发送者发出这些广播时,接收者就会得到通知了。更多关于Android系统的广播机制的知识,可以参考前面这一系列文章。然而,ContentProvider中的数据监控机制与Android系统中的广播机制又有三个主要的区别,一是前者是通过URI来把通知的发送者和接收者关联在一起的,而后者是通过Intent来关联的,二是前者的通知注册中心是由ContentService服务来扮演的,而后者是由ActivityManagerService服务来扮演的,三是前者负责接收数据更新通知的类必须要继承ContentObserver类,而后者要继承BroadcastReceiver类。之所以会有这些区别,是由于ContentProivder组件的数据共享功能本身就是建立在URI的基础之上的,因此专门针对URI来设计另外一套通知机制会更实用和方便,而Android系统的广播机制是一种更加通用的事件通知机制,它的适用范围会更广泛一些。与分析Android系统的广播机制类似,我们把ContentProvider的数据更新机制划分为三个单元进行分析,第一个单元是ContentService的启动过程,第二个单元是监控数据变化的ContentObserver的注册过程,第二个单元是数据更新通知的发送过程。与前面两篇文章和一样,本文仍然以这篇文章介绍的应用程序为例来分析ContentProvider的数据更新机制。1.ContentService的启动过程分析前面提到,在ContentProvider的数据更新通知机制中,ContentService扮演者ContentObserver的注册中心的角色,因此,它必须要系统启动的时候就启动起来,以便后面启动起来的应用程序可以使用它。在前面这篇文章中,我们提到,Android系统进程Zygote在启动的时候,在启动一个System进程来加载系统的一些关键服务,而ContentService就这些关键服务之一了。在System进程中,负责加载系统关键服务的类为SystemServer类,它定义在frameworks/base/services/Java/com/android/server/SystemServer.java文件中,它会通过启动一个线程SystemThread来加载这些关键服务:[java]viewplaincopy在CODE上查看代码片派生到我的代码片classServerThreadextendsThread{......@Overridepublicvoidrun(){......Looper.prepare();//Criticalservices...try{......ContentService.main(context,factoryTest==SystemServer.FACTORY_TEST_LOW_LEVEL);......}catch(RuntimeExceptione){......}......Looper.loop();......}}ContentService类定义在frameworks/base/core/java/android/content/ContentService.java文件中,它的main函数的实现如下所示:[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicfinalclassContentServiceextendsIContentService.Stub{......publicstaticIContentServicemain(Contextcontext,booleanfactoryTest){ContentServiceservice=newContentService(context,factoryTest);ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME,service);returnservice;}......}从这里我们就可以看到,在ContentService类的main函数中,会创建一个ContentService实例,然后把它添加到ServiceManager中去,这样,ContentService服务就启动起来了,其它地方可以通过ServiceManager来获得它的一个远程接口来使用它提供的服务。2.ContentObserver的注册过程分析在前面这篇文章介绍的应用程序Acticle中,主窗口MainActivity在创建的时候,会调用应用程序上下文的ContentResolver接口来注册一个自定义的ContentObserver来监控ArticlesProvider这个ContentProvider中的数据变化:[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicclassMainActivityextendsActivityimplementsView.OnClickListener,AdapterView.OnItemClickListener{......privateArticleAdapteradapter=null;privateArticleObserverobserver=null;......@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);......observer=newArticleObserver(newHandler());getContentResolver().registerContentObserver(Articles.CONTENT_URI,true,observer);......}privateclassArticleObserverextendsContentObserver{publicArticleObserver(Handlerhandler){super(handler);}@OverridepublicvoidonChange(booleanselfChange){adapter.notifyDataSetChanged();}}......}从ContentObserver继承下来的子类必须要实现onChange函数。当这个ContentObserver子类负责监控的数据发生变化时,ContentService就会调用它的onChange函数来处理,参数selfChange表示这个变化是否是由自己引起的,在我们这个情景中,不需要关注这个参数的值。在这个应用程序中,ArticleObserver继承了ContentObserver类,它负责监控的URI是Articles.CONTENT_URI,它的值为content://shy.luo.providers.articles/item,这个值是在这篇文章介绍的应用程序ActiclesProvider中的Articles.java文件中定义的。当所有以Articles.CONTENT_URI为前缀的URI对应的数据发生改变时,ContentService都会调用这个ArticleObserver类的onChange函数来处理。在ArticleObserver类的onChange函数中,执行的操作就是重新获取ActiclesProvider中的数据来更新界面上的文章信息列表。在ArticleObserver类的构造函数中,有一个参数handler,它的类型为Handler,它是从MainActivity类的onCreate函数中创建并传过来的。通过前面这篇文章的学习,我们知道,这个handler是用来分发和处理消息用的。由于MainActivity类的onCreate函数是在应用程序的主线程中被调用的,因此,这个handler参数就是和应用程序主线程的消息循环关联在一起的。在后面我们分析数据更新通知的发送过程时,便会看到这个handler参数是如何使用的了。下面我们就开始分析注册ArticleObserver来监控ActiclesProvider中的数据变化的过程,首先来看一下这个过程的时序图,然后再详细分析每一个步骤:这个函数定义在frameworks/base/core/java/android/content/ContentResolver.java文件中:[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicabstractclassContentResolver{......publicfinalvoidregisterContentObserver(Uriuri,booleannotifyForDescendents,ContentObserverobserver){try{getContentService().registerContentObserver(uri,notifyForDescendents,observer.getContentObserver());}catch(RemoteExceptione){}}......}当参数notifyForDescendents为true时,表示要监控所有以uri为前缀的URI对应的数据变化。这个函数做了三件事情,一是调用getContentService函数来获得前面已经启动起来了的ContentService远程接口,二是调用从参数传进来的ContentObserver对象observer的getContentObserver函数来获得一个Binder对象,三是通过调用这个ContentService远程接口的registerContentObserver函数来把这个Binder对象注册到ContentService中去。Step2.ContentResolver.getContentService这个函数定义在frameworks/base/core/java/android/content/ContentResolver.java文件中:[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicabstractclassContentResolver{......publicstaticIContentServicegetContentService(){if(sContentService!=null){returnsContentService;}IBinderb=ServiceManager.getService(CONTENT_SERVICE_NAME);......sContentService=IContentService.Stub.asInterface(b);......returnsContentService;}privatestaticIContentServicesContentService;......}在ContentResolver类中,有一个静态成员变

1 / 18
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功