This page was last modified 18:25, 28 July 2007.
Активные объекты - пример реализации
From Forum Nokia Wiki
Перевод с английского, оригинальная статья находится здесь.
Активный объект позволяет клиенту взаимодействовать с асинхронным сервис-провайдером. Для создания своего активного объекта необходимо объявить наследника класса CActive, в нем реализовать методы, с помощью которых будут создаваться асинхронные запросы, а также метод, который будет вызываться планировщиком по окончанию выполнения запроса (RunL()). Ниже представлен пример простого активного объекта:
Contents |
MyActiveObject.h
#ifndef __MYACTIVEOBJECT_H__ #define __MYACTIVEOBJECT_H__
Класс CActive объявлен в файле e32base.h - необходимо включить этот заголовочный файл.
#include <e32base.h>
Класс-наблюдатель (Observer). Используется для оповещения о завершении выполнения асинхронного запроса.
class MMyActiveObjectObserver { public:
Чистая виртуальная функция - должна быть реализована в потомках. Вызывается при завершении выполнения асинхронного запроса.
virtual void HandleRequestCompletedL(TInt aError) = 0; };
Активный объект, который позволяет использовать RMyAsyncServiceProvider.
class CMyActiveObject : public CActive { public: static CMyActiveObject* NewL(TInt aPriority); ~CMyActiveObject(); void DoAsyncAction(MMyActiveObjectObserver* aObserver); protected: // CActive void RunL(); void DoCancel(); TInt RunError(TInt aError); private: CMyActiveObject(TInt aPriority); void ConstructL(); private: RMyAsyncServiceProvider iServiceProvider; // Service provider MMyActiveObjectObserver* iObserver; // Observer }; #endif // __MYACTIVEOBJECT_H__
MyActiveObject.cpp
#include "myactiveobject.h"
Функция - фабрика для создания активного объекта. См. Двухфазное конструирование. Приоритет активного объекта передается в качестве параметра, возможные значения можно найти здесь.
CMyActiveObject* CMyActiveObject::NewL(TInt aPriority) { CMyActiveObject* self = new (ELeave) CMyActiveObject(aPriority); CleanupStack::PushL(self); self->ConstructL(); CleanupStack::Pop(); return self; }
Конструктор. Используется в функции NewL(). Здесь устанавливается приоритет активного объекта. Изменить приоритет в дальнейшем нельзя.
CMyActiveObject::CMyActiveObject(TInt aPriority) : CActive(aPriority) { }
Инициализируем активный объект.
void CMyActiveObject::ConstructL() {
Добавляем созданный активный объект в планировщик (Active Scheduler). Если этого не сделать, то при попытке использования возникнет паника E32User-CBase. Метод CActiveScheduler::Add() не является сбрасываемым, следовательно, его можно вызывать и из конструктора.
CActiveScheduler::Add(this);
Выполняем соединение с асинхронным сервис-провайдером. Генерируем сброс в случае неудачи.
User::LeaveIfError(iServiceProvider.Connect()); }
Деструктор.
CMyActiveObject::~CMyActiveObject() {
Метод Cancel() всегда должен вызываться в деструкторе активного объекта, для того чтобы отменить выполнение текущего запроса, если он есть. Если текущего запроса нет - метод Cancel() ничего не делает. Если же запрос есть и Cancel() не был вызван при уничтожении объекта - генерируется паника E32User-CBase 40.
Cancel();
Закрытие соединения с сервис-провайдером.
iServiceProvider.Close(); }
Следующий метод должен быть вызван пользователем, чтобы начать асинхронную операцию. Аргумент - указатель на объект класса-наблюдателя, чей метод HandleRequestCompletedL() будет вызван по окончанию выполнения асинхронной операции.
void CMyActiveObject::DoAsyncAction(MMyActiveObjectObserver* aObserver) {
С помощью утверждения выполняется проверка, что на данный момент нет выполняющегося запроса. Если выполняющийся запрос есть - генерируется паника с кодом EAlreadyActive. Эта проверка позволяет предотвратить панику E32User-CBase 42 которая может быть сгенерированна при вызове SetActive(). Подробнее о паниках и утверждениях можно прочитать здесь.
__ASSERT_ALWAYS(!IsActive(), User::Panic(KMyActivePanic, EAlreadyActive));
Проверка указателя aObserver.
__ASSERT_ALWAYS(aObserver, User::Panic(KMyActivePanic, ENoObserver));
Выполняется передача запроса сервис-провайдеру. В качестве параметра передается ссылка на iStatus. Сервис-провайдер устанавливает iStatus равным KRequestPending. Как только сервис-провайдер закончит выполнение запроса, планировщик (Active Scheduler) установит значение iStatus равным результату выполненной операции (KErrNone если выполнение прошло успешно, или коду ошибки).
iServiceProvider.DoService(iStatus);
Информируем планировщик о том, что активный объект ожидает завершения выполнения операции.
SetActive(); }
Метод RunL() будет вызван планировщиком, когда выполнение запроса будет завершено. Все активные объекты должны реализовать этот метод. Планировщик выполняет его в рамках ловушки (TRAP) и, если происходит сброс, вызывает метод RunError().
void CMyActiveObject::RunL() {
iStatus содержит результат выполнения операции. Если была ошибка - генерируется сброс.
User::LeaveIfError(iStatus.Int());
Этот код выполнится, только если запрос был обработан успешно. Вызывается метод наблюдателя, чтобы проинформировать о завершении выполнения запроса.
iObserver->HandleRequestCompletedL(KErrNone); }
Все активные объекты должны реализовывать метод DoCancel(). Он вызывается в методе Cancel() и прерывает выполнение текущего запроса.
void CMyActiveObject::DoCancel() { iServiceProvider.Cancel(); }
Реализовывать метод RunError() не обязательно, но обычно это очень полезно.
Этот метод вызывается планировщиком, если во время выполнения RunL() произошел сброс. RunError() должен обработать полученный в качестве параметра код ошибки (если это возможно) и возвратить KErrNone. Реализация этого метода по умолчанию просто возвращает полученный код ошибки aError.
Если возвращаемое методом RunError() значение не является KErrNone, тогда планировщик вызывает собственную функцию Error(). Функция CActiveScheduler::Error() генерирует панику E32USER-CBase 47 (такое поведение
можно изменить, если реализовать свой планировщик - для этого нужно создать наследника CActiveScheduler и перекрыть метод Error(). Обычно, реализация собственного планировщика является излишней).
TInt CMyActiveObject::RunError(TInt aError) {
Информируем наблюдателя об ошибке. Наблюдатель может корректно обработать возникшую ошибку и, возможно, выполнить другой асинхронный запрос. Выполнение RunError() не должно привести к сбросу, поэтому вызов HandleRequestCompletedL() происходит в рамках ловушки. Используется TRAP_IGNORE так как в этом методе неизвестно каким образом обрабатывать возможный сброс.
TRAP_IGNORE(iObserver->HandleRequestCompletedL(aError)); return KErrNone; }
Внутренние ссылки
Активные объекты (Active Objects) в Symbian ОС
Активные объекты - часто встречающиеся ошибки реализации
Внешние ссылки
CActive в библиотеке разработчика Symbian OS
CActiveScheduler в библиотеке разработчика Symbian OS
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| RMobileUssdMessaging | truf | Russian Developer Forum - Форум Российских разработчиков | 30 | 2008-02-16 19:05 |
| CAknView | b_monkey | Russian Developer Forum - Форум Российских разработчиков | 7 | 2007-12-04 12:12 |
| Делаем основной цикл игры | Ecconaut | Russian Developer Forum - Форум Российских разработчиков | 17 | 2007-12-12 04:32 |
| NokiaCLFileTransfer | soumi | Russian Developer Forum - Форум Российских разработчиков | 3 | 2008-07-02 09:50 |
| Присоединение MBM файлов | LuckyBeaver | Russian Developer Forum - Форум Российских разработчиков | 7 | 2008-01-20 11:17 |
