在单线程中,活动对象框架采用非抢占式多任务调度机制。一旦某个活动对象正在进行事件处理,其它活动对象的事件处理必须等到正在进行事件处理的活动对象运行完毕后才可以运行,即它是不可被抢占的。活动对象类必须直接或者间接的继承自CActive类,这个类被定义在e32base.h里面。CAcitve类是一个抽象类,具有两个纯虚函数,RunL()和DoCancel(),因此要想实例化这个活动对象必须要在子类中实现这两个纯虚方法。
1、构造活动对象
在类CAtive里面枚举TPriority定义了一组优先级的值。一般,优先级的值使用CActive::EPriorityStandard(=0),除非有其它更好的理由使用别的值。在构造函数里面,活动对象应该调用CActiveScheduler::Add()方法把它加到活动调度器里面。
2
3 2 {
4
5 3....
6
7 4 }
8
9 5void CMyActiveObject::ConstructL()
10
11 6 {
12
13 7 ....
14
15 8 CActiveScheduler::Add( this); // Add to scheduler
16
17 9 }
18
19
2、异步请求
使用活动对象的目的就是发送异步请求,由于每个活动对象只能有一个未处理的请求,因此对于请求的发送应进行严格的检查。通常每次发送请求后都要执行SetActive()方法,表明请求已经提交并且当前是未完成的,而调度器当检测出符合条件的活动对象后会将它的活动状态设为notactive,因此可以通过IsActive() 的返回值来判断是否有未完成的请求。如果有一个未完成的请求,还在接着发送就会出现Panic。
活动对象提交一个请求到异步服务提供者,会传递一个TRequestStatus成员变量(iStatus),服务提供者必须在开始异步服务之前把iStatus值设置为KRequestPending。
异步请求发送的过程图
3、取消异步请求
活动对象的基类CActive 提供了一个纯虚方法 DoCancel(),重载这个方法以实现取消请求的功能,但是需要注意的是应用程序以及活动对象本身都不能直接调用这个方法,而是应该调用Cancel()方法。因为Cancel()方法中首先检查活动标记,对于处于活动状态的活动对象调用DoCancel(),然后将活动标记设为EFalse。调用Cancel() 后如果请求被取消,服务提供者仍然会发送一个异步事件,并将状态标记的返回值设为KErrCancel。
4、异步服务完成后的处理过程
每个活动对象必须实现从基类CActive继承过来的纯虚方法RunL(),这是事件处理函数,当来自异步服务提供者的服务请求完成事件发生时,活动调度器就会选择调用相关活动对象的RunL()方法。
RunL()应该根据事件完成返回的code检查异步服务请求是否成功完成,这个返回值一个32位的整型值,也就是 TRequestStatus对象中的完成码(iStatus)。根据这个结果,RunL()会有不同的执行代码,其中有可能提交另一个请求或执行诸如写log文件之类的操作,以便将错误信息或重要的值输出到文件中。根据不同的要求,RunL()函数代码的复杂度差别很大。有一个关键的问题是由于RunL()开始执行后,它就无法被其他活动对象的事件处理程序所抢占。因此,RunL()其中的代码段应该尽可能短小以便能够很快地被执行完,这样其他的事件的处理才不会发生延误。
基类CActive还提供了一个重要的方法就是RunError(),他是一个虚方法,如果当RunL()发生Leave时,活动调度器会使用TRAP捕获此异步,然后调用这个方法。如果RunError()方法没有对异常做处理,那么调度器就要负责处理该异常。如果希望处理RunL()的leaves,应该重写CActive::RunError()这个方法处理异常。