[消息,异步服务和活动对象]
MFC在对无论是初级还是了解驱动他们应用程序的消息循环和调度机制的高级程序员隐藏Windows消息范例方面做得很好。在Symbian 操作系统中,驱动应用程序的是一套完全不同又十分强大的机制,被称为活动对象。它与Symbian操作系统的客户端-服务器端结构紧密结合,提供了各种系统服务,同时也可以为程序员来给他们可能需要为应用程序创建的任何异步服务建立干净、标准的接口。
简而言之,CActiveScheduler执行了Windows消息循环,在一个给定线程内提供了共用的多任务,CActive(一个活动对象)充当了消息处理者。在Symbian 的UI 框架中,这要比MFC 把消息隐藏得更好:接收到的消息总是由框架调度给预先定义的可以被应用程序重载的方法——比如OfferKeyEventL(处理键盘输入)。
定时器是使用了活动对象框架的简单系统服务的一个实例。不同于Windows 中调用StartTimer 来触发WM_TIMER 消息的做法,Symbian 操作系统中是由一个CTimer 对象与系统时钟服务进行交互,RTimer 与其RunL 函数根据由API 规定的时间间隔被调用。程序员从CTimer 继承到一个对象,并重载RunL 方法。
其它的异步系统服务,如Nokia 7650 上的照相机功能也是通过类似方法提供的。CCameraManager 定义了一个活动对象提出拍照操作的请求并随即获得通知。实际的异步服务是由RCameraServ 提供的,但是典型的程序员根本用不着处理任何客户端-服务器端或者显式的进程间通信问题。
使用活动对象时,头脑中时刻牢记活动对象何时按预定计划执行这个很简单的准则非常重要。这就是说,到底什么时候CActiveScheduler 会调用一个CActive 对象的RunL 方法呢?
·CActive 对象必需是“活动”的。这是通过调用Cactive::SetActive 实现的,通常在活动对象自己对应用程序某个请求做出的响应中完成。
·CActive 对象的状态,由成员变量iStatus 所示,一定不能为KRequestPending。这个值表示该对象正在等待服务完成。通常在提出一个服务请求时变量iStatus 才会被服务提供者设为KRequestPending。iStatus 随后在服务结束时被服务者提供者更新。
·CActiveScheduler 需要接收到一个信号——该信号由异步服务在结束时发出。
当异步进程对应用程序发出结束信号,然而没有准备好的CActive 对象时,就会产生一个“迷失”信号。这在以下几种情况下可能发生:
·你忘记了使用CActive::SetActive 使活动对象处于“活动”状态。
·服务提供者在发出操作完成信号时忘记将iStatus 置为非KRequestPending 的值。这只会在你写了错误的服务提供者时出现——典型的应用程序会使用系统定义的服务。
·服务提供者给同一个操作发出了不只一个终止信号。
第三种情况在服务提供者设计不够仔细的情况下可能发生。例如,有一个服务已经结束并且对客户端通知了这一事实,但是客户端恰恰在收到这个通知之前发出了取消服务的请求。服务提供者必需忽略这一当前不合理的请求。要是服务提供者没有忽略这一请求,而是对它做出响应并给出一个附加信号说已经结束了,会是怎么样呢?在这种情况中,附加的信号最终就会成为“迷失”信号,并会引起程序出错。这对于纠错来说很困难,因为“迷失”信号是被CActiveScheduler 检测到的,没有显示是什么CActive 对象的责任。
CActive 对象必需确保在各种情况下与服务相关联的终止信号都恰当。在解除程序中应该典型的具有一个CActive::Cancel 调用。如果Cancel没有被调用,而对象在有请求仍被挂起时就被删除,错误就会发生。而且,每个CActive 对象必需以确保任何由该对象请求的服务都被取消的方式执行CActive::DoCancel,否则CActive::Cancel 就会一直等待服务提供者的终止信号。这两种错误都很难被检测到,因为它们只在存在明显的请求时才会被发现。