Active object example

A simple 'hello world' style active object.

The example active object encapsulates an RTimer and calls the asynchronous function RTimer::After().

Active objects classes must derive from CActive.
class CMyTimer : public CActive
    {
public:

  // Factory functions to instantiate the class.
  static CMyTimer* NewLC();
  static CMyTimer* NewL();

  // Destructor.
  ~CMyTimer();

  // Inherited pure virtual functions.
  void DoCancel();
  void RunL();

  // Error handling.
  TInt RunError( TInt aError );

  // The function that makes the asynchronous request.
  void MakeRequest( TUint aDelay );
protected:

  // First and second phase constructors, called by
  // the factory functions NewL() and NewLC()
  CMyTimer();
  void ConstructL();
private:

  // The object used to make the asynchronous request.
  // This is often called the 'asynchronous service provider'.
  RTimer iTimer;
    };
Here is some sample code to instantiate the active object and make an asynchronous request:
// Create an active scheduler for the thread.
// An active scheduler is needed to manage one or more active 
// objects.
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;

// Use the cleanup stack to ensure the active scheduler
// is deleted in the event of a leave.
CleanupStack::PushL( scheduler );

// Install the active scheduler for the current thread.
CActiveScheduler::Install( scheduler );

// Instantiate the active object.
CMyTimer* timer =  CMyTimer::NewLC();

// Make an asynchronous request.
timer->MakeRequest( 2000000 );

// Start the active scheduler's loop.
CActiveScheduler::Start();

// Clean up.
CleanupStack::PopAndDestroy( 2, scheduler );

Note. The Qt and AVKON application frameworks create, install, and start the active scheduler for the main application thread. The code above is for tutorial purposes only.

The asynchronous request is made as a result of the call to MakeRequest():
void CMyTimer::MakeRequest(TUint aDelay)
 {
  // Cancel a previous request. A single active
  // object can only have one request outstanding
  // at once.
  Cancel();

  // Pass in the active object's TRequestStatus
  // member iStatus when making the request.  
  iTimer.After( iStatus, aDelay );

  // Inform the active scheduler that the active
  // object has an outstanding asynchronous request.
  SetActive();
 }
When the request completes the active scheduler will call the active object's RunL() method. RunL() is a pure virtual method that you must override. Use this method to define the behaviour required as a result of request completion.
void CMyTimer::RunL()
  {
  // Take appropriate action as a result of the
  // completion of the request. You could make another
  // request, using this or another active object.
  }

Cancelling a request

An active object class must override the pure virtual DoCancel() method of the base class to terminate a request by calling the appropriate cancellation method on the asynchronous service provider.
CMyTimer::~CMyTimer()
  {
  // Invoke the base class Cancel(). This calls
  // our DoCancel() override if a request is
  // outstanding.
  Cancel();

  // Clean up RTimer.
  iTimer.Close();
  }

void CMyTimer::DoCancel()
  {
  // Call cancellation function of the asynchronous
  // service provider.
  iTimer.Cancel();
  }

Error handling

If the RunL() callback method of an active object leaves, the framework invokes the virtual RunError() method of the active object. If you are able to handle the error, return KErrNone from RunError().
// Called by the active scheduler if RunL() leaves.
// The parameter aError contains the leave code.
TInt CMyTimer::RunError( TInt aError )
  {
  // Take action to handle the error
  ...
  // Indicate that the error has been handled.
  return KErrNone;
  }

If you choose not to handle the leave inside RunError() the framework calls CActiveScheduler::Error(). The default implementation of this virtual method is to panic the thread (EUSER-CBase 47).

Member functions to create the active object

For completeness here are the definitions of the remaining member functions of the example active object. Note that the class uses the two-phase construction idiom. For further details see Two-phase construction.
// Factory function.
CMyTimer* CMyTimer::NewL()
  {
  CMyTimer* self = NewLC();
  CleanupStack::Pop( self );
  return self;
  }

// Factory function that returns the address
// of the object on the cleanup stack.
CMyTimer* CMyTimer::NewLC()
  {
  CMyTimer* self = new (ELeave) CMyTimer();
  CleanupStack::PushL( self );
  self->ConstructL();
  return self;
  }

// Constructor sets the priority of the 
// active object.  The active scheduler stores the
// active objects in a priority ordered list.
CMyTimer::CMyTimer()
  : CActive( CActive::EPriorityStandard ) 
	{}

// Second phase constructor.
void CMyTimer::ConstructL()
{
  // Initialize the asynchronous service provider.
  User::LeaveIfError( iTimer.CreateLocal() );

  // Add the active object to the active
  // scheduler's list.
  CActiveScheduler::Add( this );
}

Related concepts