×
Namespaces

Variants
Actions

Активные объекты - пример реализации

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

Статья
Перевод:
Оригинал: Active object
Den123
Последнее редактирование: hamishwillee (09 Dec 2011)

Активный объект позволяет клиенту взаимодействовать с асинхронным сервис-провайдером. Для создания своего активного объекта необходимо объявить наследника класса 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

This page was last modified on 9 December 2011, at 04:01.
117 page views in the last 30 days.