一、CActive
可以理解为Windows的消息循环之类的东西;执行过程参照此图:
二、Symbian 的消息循环:
EventProcessingLoop()
{
// Suspend the thread until an event occurs
User::WaitForAnyRequest();
// Thread wakes when the request semaphore is signaled
// Inspect each active object added to the scheduler,
// in order of decreasing priority
// Call the event handler of the first which is active & completed
FOREVER
{
// Get the next active object in the priority queue
// the activeObject is getting from the priority queue
if (activeObject->IsActive())
&& (activeObject->iStatus!=KRequestPending)
{// Found an active object ready to handle an event
// Reset the iActive status to indicate it is not active
activeObject->iActive = EFalse;
// Call the active object’s event handler in a TRAP
TRAPD(r, activeObject->RunL());
if (KErrNone!=r)
{// event handler left, call RunError() on active object
r = activeObject->RunError();
if (KErrNone!=r) // RunError() didn’t handle the error,
Error(r); // call CActiveScheduler::Error()
}
break; // Event handled. Break out of lookup loop & resume
}
} // End of FOREVER loop
}
三、消息循环流程
四、但Symbian 操作系统定义好了以上类,只要调用以下代码就完成消息循环:
CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
用户可以直接使用 CActiveScheduler 也可以从其派生,定义自己的一些特性。
五、Cancel
执行取消必须在被调用到对应对象的 RunL之前,如果已经在调用RunL,再调用Cancel 是没有办法取消的,除非在RunL里面做判断;(自己总结的,不知道对错)
六、CIdle 类和CPeriodic
在空闲时刻执行和定期执行;
使用状态机,如下例:
// Provides the "step" functions
class CServiceProvider : public CBase
{
public:
static CServiceProvider* NewL();
~CServiceProvider() {};
public:
void GetData(const TDesC& aSource, HBufC8*& aData,
TRequestStatus& aStatus);
void CancelGetData();
TInt TranslateData(TDes8& aData);
void SendData(const TDesC& aTarget, const TDesC8& aData,
TRequestStatus& aStatus);
void CancelSendData();
protected:
CServiceProvider(){};
};
void CServiceProvider::GetData(const TDesC& aSource, HBufC8*& aData,
TRequestStatus& aStatus)
{
aStatus = KRequestPending;
// Retrieves data from aSource using the asynchronous overload of
// RFile::Read() and writing to aData (re-allocating it if
// necessary). aStatus is completed by the file server when the
// read has finished
...
}
void CServiceProvider::CancelGetData() {...}
TInt CServiceProvider::TranslateData(TDes8& aData)
{// Synchronously translates aData & writes into same descriptor
...
return (translationResult);
}
void CServiceProvider::SendData(const TDesC& aTarget, const TDesC8&
aData, TRequestStatus& aStatus)
{
aStatus = KRequestPending;
// Writes data to aTarget using the asynchronous overload of
// RFile::Write(), which completes aStatus
...
}
void CServiceProvider::CancelSendData() {...}
class CStateMachine : public CActive
{
public:
~CStateMachine();
static CStateMachine* NewLC();
void SendTranslatedData(const TDesC& aSource, const TDesC& aTarget,
TRequestStatus&);
protected:
enum TState { EIdle, EGet, ETranslate, ESend};
protected:
CStateMachine();
void InitializeL(const TDesC& aTarget);
void Cleanup();
protected:
virtual void DoCancel(); // Inherited from CActive
virtual void RunL();
// The following base class method is not overridden because
// RunL() cannot leave
// virtual TInt RunError(TInt aError);
private:
CServiceProvider* iService;
TState iState;
private:
HBufC* iTarget;
HBufC8* iStorage;
TRequestStatus* iClientStatus;
};
CStateMachine::CStateMachine()
: CActive(EPriorityStandard) {CActiveScheduler::Add(this);}
CStateMachine::()
{
Cancel();
Cleanup();
}
void CStateMachine::InitializeL(const TDesC& aTarget)
{
// Store this to pass to CServiceProvider later
iTarget = aTarget.AllocL();
// To store retrieved data
iStorage = HBufC8::NewL(KStandardDataLen);
}
void CStateMachine::Cleanup()
{// Pointers are NULL-ed because this method is called outside
// the destructor
iState = EIdle;
delete iTarget;
iTarget = NULL;
delete iStorage;
iStorage = NULL;
}
const TInt KStandardDataLen = 1024;
// Starts the state machine
void CStateMachine::SendTranslatedData(const TDesC& aSource,
const TDesC& aTarget, TRequestStatus& aStatus)
{
__ASSERT_ALWAYS(!IsActive(), User::Panic(KExPanic, KErrInUse));
ASSERT(EIdle==iState);
// Store the client request status to complete later
iClientStatus = &aStatus;
iClientStatus = KRequestPending;
TRAPD(r, InitializeL(aTarget);
if (KErrNone!=r)
{// Allocation of iTarget of iStorage failed
Cleanup(); // Destroys successfully allocated member data
User::RequestComplete(iClientStatus, r);
}
else
{
iService->GetData(aSource, iStorage, iStatus);
iState = EGet;
SetActive();
}
}
// The state machine is driven by this method
void CStateMachine::RunL()
{// Inspects result of completion and iState
// and submits next request (if required)
ASSERT(EIdle!=iState);
if (KErrNone!=iStatus.Int())
{// An error - notify the client and stop the state machine
User::RequestComplete(iClientStatus, iStatus.Int());
Cleanup();
}
else
{
if (EGet==iState)
{// Data was retrieved, now translate it synchronously
TPtr8 ptr(iStorage->Des());
iService->TranslateData(ptr);
iState = ETranslate;
// Self completion –described later
TRequestStatus* stat = &iStatus;
User::RequestComplete(stat, r);
SetActive();
}
else if (ETranslate==iState)
{// Data was translated, now send it asynchronously
TInt r = iService->SendData(*iTarget, *iStorage, iStatus);
iState = ESend;
SetActive();
}
else
{// All done, notify the caller
ASSERT(ESend==iState);
User::RequestComplete(iClientStatus, iStatus.Int());
Cleanup();
}
}
}
void CStateMachine::DoCancel()
{
if (iService)
{
if (CStateMachine::EGet = =iState)
{
iService->CancelGetData();
}
else if (CStateMachine::ESend = =iState)
{
iService->CancelSendData();
}
}
if (iClientStatus)
{// Complete the caller with KErrCancel
User::RequestComplete(iClientStatus, KErrCancel);
}
Cleanup();
}