Symbian中使用活动对象的三种典型设计

来源:百度文库 编辑:神马文学网 时间:2024/04/28 20:40:59
Symbian中使用活动对象的三种典型设计
 
发表时间:2008-12-18 2:12:59  浏览次数:214
 
    Symbian中活动对象的使用是很频繁的(活动对象的理论我不多说了,关心的朋友自己去查资料,跟Windows平台中的ActiveX对象一个样,对事件的驱动和处理过程也跟它一样,或者说,举个简单的例子,跟Ajax的异步传输一样.因为Symbian的活动对象本来就是用于异步请求的事件处理的).使用活动对象的典型方式我认为有三个:    1.状态机(通俗的说就是在同一线程同一活动对象中处理多步骤的异步请求)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;
    // 用RFile::Read()的异步重载形式从aSource中获取数据,并写入aData(如果必要,对其
    // 重新分配空间),当读取完成,则由文件服务器将aStatus标为完成状态
}void CServiceProvider :: CancelGetData() {...}void CServiceProvider :: TranslateData(TDes8 & aData) {
    // 同步解析数据并写入同一个描述符中
    ...
    return translationResult;
}void CServiceProvider :: SendData(const TDesC & aTarget, const TDesC8 & aData, TRequestStatus & aStatus) {
    aStatus = KRequestPending;
    // 用RFile::Write()的异步重载形式向aTarget中写入数据,该函数在完成时设置aStatus状态
    ...
}void CServiceProvider :: CancelSendData() {...}const TInt KStandardDataLen = 1024;class CStateMachine : public CActive {
public:
    ~CStateMachine();
    state CStateMachine * NewLC();
    void SendTranslatedDate(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();
    virtual void RunL();
    // RunError()我没有实现,因为RunL()在这个例子中不会Leave,但是这个声明是必须的(受C++语法限制)
    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 :: ~CStateMachine() {
    Cancel();
    Cleanup();
}void CStateMachine :: InitializeL(const TDesC & aTarget) {
    // 将其保存起来,后面传递给CServiceProvider
    iTarget = aTarget.AllocL();
    // 保存接收到的数据
    iStorage = HBufC8::NewL(KStandardDataLen);
}void CStateMachine :: Cleanup() {
    iState = EIdle;
    delete iTarget;
    iTarget = NULL;
    delete iStorage;
    iStorage = NULL;
}void CStateMachine :: SendTranslatedData(const TDesC & aSource, const TDesC & aTarget, TRequestStatus & aStatus) {
    __ASSERT_ALWAYS(!IsActive, User::Panic(KExPanic, KErrInUse));
    ASSERT(EIdle == iState);
    iClientStatus = &aStatus;
    *iClientStatus = KRequestPending;
    TRAPD(r, InitializeL(aTarget));
    if(KErrNone != r) {
        Cleanup();  
        User::RequestComplete(iClientStatus, r);
    } else {
        iService -> GetData(aSource, iStorage, iStatus);
        iState = EGet;
        SetActive();
    }
}void CStateMachine :: RunL() {
    ASSERT(EIdle != iState);
    if(KErrNone != iStatus.Int()) {
        User :: RequestComplete(iClientStatus, iStatus.Int());
        Cleanup();
    } else {
        if(EGet == iState) {
            TPtr8 ptr(iStroage.Des());
            iService -> TranslateData(ptr);
            iState = ETranslate;
            TRequestStatus * stat = &iStatus;
            User::RequestComplete(stat, r);
            SetActive();
        } else if(ETranslate == iState) {
            TInt r = iService -> SendData(*iTarget, *iStorage, iStatus);
            iState = ESend;
            SetActive();
        } else {
            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) {
        User :: RequestComplete(iClientStatus, KErrCancel);
    }
}    2.长线任务(通俗的说,也就是在一个优先级低的活动对象中持续处理一个分成很多步的任务,这些任务可以不是异步的,每个步骤之间是自驱动或者叫自完成的)class CLongRunningCalculation : pulbic CBase {
public:
    static CLongRunningCalculation * NewL();
    TBool StartTask();
    TBool DoTaskStep();
    void EndTask();
    ...
};TBool CLongRunningCalculation :: DoTaskStep() {
    // 执行一个任务步骤,如果还有任务要做则返回ETrue,如果任务完成了,返回EFalse
}_LIT(KExPanic, "CActiveExample");class CBackgroundRecalc : public CActive {
public:
    // NewL,析构函数等
public:
    void PerformRecalculation(TRequestStatus & aStatus);
protected:
    CBackgroundRecalc();
    void ConstructL();
    void Complete();
    virtual void RunL();
    virtual void DoCancel();
private:
    CLongRunningCalculation * iCalc;
    TBool iMoreToDo;
    TRequestStatus * iCallerStatus;
};CBackgroundRecalc :: CBackgroundRecalc() : CActive(EPriorityIdle) {
    CActiveScheduler :: Add(this);
}void CBackgroundRecalc :: PerformRecalculation(TRequestStatus & aStatus) {
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    __ASSERT_ALWAYS(!IsActive(), User :: Panic(KExPanic, KErrInUse));
    iMoreToDo = iCalc -> StartTask();
    Complete();
}void CBackgroundRecalc :: Complete() {
    TRequestStatus * status = &iStatus;
    User :: RequestComplete(status, KErrNone);
    SetActive();
}void CBackgroundRecalc :: RunL() {
    if(!MoreToDo) {
        iCalc -> EndTask();
        User :: RequestComplete(iCallerStatus, iStatus.Int());
    } else {
        iMoreToDo = iCalc -> DoTaskStep();
        Complete();
    }
}void CBackgroundRecalc :: DoCancel() {
    if(iCalc) {
        iCalc -> EndTask();
    }
    if(iCallerStatus) {
        User :: RequestComplete(iCallerStatus, KErrCancel);
    }
}    3.多线程(通俗的说,就是活动对象开启另外一个线程来处理请求,这样不会阻塞某些重要的请求完成)
_LIT(KThreadName, "ExampleThread");
TInt SynchronousTask(); class CAsyncTask : public CActive {
public:
    ~CAsyncTask();
    static CAsyncTask * NewLC();
    void DoAsyncTask(TRequestStatus & aStatus);
protected:
    virtual void DoCancel();
    virtual void RunL();
    virtual TInt RunError(TInt anError);
private:
    CAsyncTask();
    void ConstructL();
private:
    TRequestStatus * iCaller;
    RThread iThread;
};CAsyncTask :: CAsyncTask() : CActive(EPriorityStandard) {
    CActiveScheduler :: Add(this);
}CAsyncTask :: ~CAsyncTask() {
    Cancel();
}void CAsyncTask :: DoAsyncTask(TRequesStatus & aStatus) {
    if(IsActive()) {
        TRequestStatus * status = &aStatus;
        User :: RequestComplete(status, KErrAlreadyExits);
        return;
    }
    iCaller = &aStatus;
    TInt res = iThread.Create(KThreadName, ThreadEntryPoint, KDefaultStackSize, NULL, NULL);
    if(KErrNone != res) {
        User :: RequestComplete(iCaller, res);
    } else {
        *iCaller = KRequestPending;
        iStatus = KRequesPending;
        SetActive();
        iThread.Logon(iStatus);
        iThread.Resume();
    }
}TInt CAsyncTask :: ThreadEntryPoint(TAny * /* aParameters */) {
    TInt res = SynchronousTask();
    RThread().Kill(res);
    return KErrNone;
}void CAsyncTask :: DoCancel() {
    TExitType threadExitType = iThread.ExitType();
    if(EExitPending == threadExitType) {
        iThread.LogonCancel();
        iThread.Kill(KErrCancel);
        iThread.Close();
        User :: RequestComplete(iCaller, KErrCancel);
    }
}void CAsyncTask :: RunL() {
    TExitType threadExitType = iThread.ExitType();
    if(EExitPending == threadExitType) {
        iThread.Kill(KErrNone);
    }
    User :: RequestComplete(iCaller, iStatus.Int());
    iThread.Close();
}TInt CAsyncTask :: RunError(TInt anError) {
    if(iCaller) {
        User :: RequestComplete(iCaller, anError);
    }
    return KErrNone;
}