Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

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

From 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 01:01.
328 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×