8.2 数据更新通知机制分析
何为数据更新通知?先来看日常生活中的一个例子。
笔者所在公司采用BugZilla来管理Bug。在日常工作中,笔者和同事们的一部分工作就是登录BugZilla查询各自名下的Bug并修改它们。如何跟踪自己的Bug呢?其实,以上描述中已经提到了一种方法,即登录BugZilla并查询。除此之外,BugZilla还支持另一种方法,即为每个Bug设置一个关系人列表,一旦该Bug的状态发生变化,BugZilla就会给该Bug关系人列表中的人发送邮件。
上例中提到的第二种方法就是本节要分析的数据更新通知机制。一般说来,领导和项目经理(PM)使用第一种方法的居多,因为他们需要不定时地查询和统计全局Bug的情况。而程序员使用第二种方法较多(也许是没办法的事情吧,谁会情愿主动查询自己的Bug呢?)。
类似的通知机制在日常生活中的其他地方还有使用。在操作系统中,这种通知机制同样也广泛存在。例如,在OS中,设计人员一般会安排外部设备以中断的方式通知CPU并让其开展后续处理,而不会让CPU去轮询外设的状态。
现在回到Android平台,如果程序需要监控某数据项的变化,可以采用一个类似while循环的语句不断查询它以判断其值是否发生了变化。显而易见,这种方式的效率很低。有了通知机制以后,程序只需注册一个ContentObserver实例即可。一旦该项数据发生变化,系统就会通过ContentObserver的onChange函数来通知我们。与前面所述的轮询相比,此处的通知方式明显更高效。
通过上面的描述可以知道,通知机制的实施包括两个步骤:第一步,注册观察者;第二步,通知观察者。在Android平台中,这两步都离不开ContentService,下面来认识一下它。
提示 在设计模式中,通知机制对应的模式是Observer模式,即观察者模式。
8.2.1 初识ContentService
SystemServer创建ContentService的代码非常简单,如下所示:
[—>SystemServer. java:ServerThread.run]
public void run(){
……
ContentService.main(context,
factoryTest==SystemServer.FACTORY_TEST_LOW_LEVEL);
……
}
以上代码中直接调用了ContentService的main函数。在一般情况下,该函数第二个参数为false。此main函数的代码如下:
[—>ContentService. java:main]
public static IContentService main(Context context, boolean factoryTest){
//构造ContentService实例
ContentService service=new ContentService(context, factoryTest);
//将ContentService注册到ServiceManager中,其注册名叫content
ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME,
service);
return service;
}
ContentService的构造函数的代码如下:
[—>ContentService. java:ContentService]
ContentService(Context context, boolean factoryTest){
mContext=context;
mFactoryTest=factoryTest;
getSyncManager();//获取同步服务管理对象,接下来看它的代码
}
[—>ContentService. java:getSyncManager]
private SyncManager getSyncManager(){
synchronized(mSyncManagerLock){
try{
//创建一个SyncManager实例,它是ContentService中负责数据同步服务的
//主力成员。留待8.4节再详细分析它
if(mSyncManager==null)mSyncManager=new
SyncManager(mContext, mFactoryTest);
}……
return mSyncManager;
}
}
看完以上代码读者可能会觉得ContentService比较简单。其实,ContentService中最难实现的功能是数据同步服务,不过该功能的实现都封装在SyncManager及相关类中了,所以在分析通知机制时不会和数据同步服务有太多瓜葛。
下面来分析通知机制实施的第一步,即注册ContentObserver。该步骤由ContentResovler提供的registerContentObserver函数来实现。