您的位置:首页 > 移动开发

应用程序架构(Application Framework)

2010-08-08 13:20 141 查看
1、S60应用程序架构

S60平台在底层Uikon应用程序框架上添加了一个用户界面层(Avkon)。Avkon提供了一套特别为S60设计的UI组件和应用程序框架。



1.1、S60应用程序结构



1.1.1、模型(Model)—视图(View)—控制器(Controller)模式(MVC)



MVC模式在S60 UI应用程序中是一个通用的设计模式。应用程序被分离成不同的逻辑部分;它们包装了应用程序的不同方面。每个部分都用特殊的任务。MVC模式分离了应用程序设计,使模型(Model)的代码得到重用。

模型(Model):
封装了应用程序的状态和功能。
通知视图(View)进行切换。
响应来自视图(View)的状态查询。

视图(View):
呈现模型(View)。
接收来自模型(Model)的视图更新通知。
将用户的输入发送给控制器(Controller)。

控制器(Controller):
定义了应用程序的行为。
将用户操作与模型(Model)更新相映射。
响应视图(View)切换请求。

1.1.2、S60应用程序结构和MVC

S60应用程序通常分离成两大部分,引擎(Engine)和UI。应用程序引擎,也就是应用程序模型,用来处理逻辑运算和数据结构表示。应用程序UI,用来在屏幕上显示应用程序的数据和全部的行为。在基于S60应用程序框架下,实现引擎和UI分离模式有三种方式:传统的Symbian OS应用程序构架、对话框构架、视图切换构架。不同的构架只反映UI的实现,应用程序类(CAknApplication继承类)和文档类(CAknDocument)并没有区别。



应用程序UI的组成:

CAknApplication继承类:
应用程序框架的启动对象。
定义了应用程序的性质。
创建文档(CAknDocument)类。

CAknDocument继承类:
创建AppUi(Controller)。
提供了应用程序数据的持久化功能。

CAknAppUi或CAknViewAppUi继承类(Controller):
基类的选择依赖于应用程序架构。
处理应用程序事件。
控制应用程序模型(Model)。
负责切换视图(View)。

CCoeControl继承类(View):
显示模型(Model)状态。
接收用户输入。
向控制器通知相关事件。
根据模型(Model)变化更新显示。

应用程序引擎(Engine):
封装了应用程序数据和状态。
封装了非UI依赖的功能,能够在其他UI平台重用。
通常以类库的形式实现。
由AppUi直接操作。

1.2、传统的Symbian OS 应用程序架构



1.3、对话框(Dialog)架构



1.4、视图切换架构

视图切换架构是一种机制,它允许应用程序注册视图,并且在任意时刻只有一个视图被激活。视图切换架构并没有规定视图的具体内容,而是为视图在屏幕上显示提供了支持。



与传统的Symbian OS应用程序架构不同的是,AppUi类(Controller)继承自CAknViewAppUi,并且引入了一个新类CAknView作为AppUi(Controller)和容器(Control)之间的媒介。在视图切换架构中,CAknView派生类称为Avkon视图(View),它拥有一个容器。AppUi创建每个Avkon视图并且在服务器端进行注册。切换视图时使用视图UID进行切换。



1.4.1、创建视图

CAknView派生类实例的创建通常在AppUi对象的ConstructL()方法中进行。该方法中将所有的视图进行注册,并设置一个默认视图:

void CMyViewArchAppUi::ConstructL()

{

BaseConstructL();

CMyViewArchAppView1* view1 = new(ELeave) CMyViewArchAppView1;

CleanupStack::PushL(view1);

view1->ConstructL();

AddViewL(view1); // Transfer ownership to CAknAppUi.

CleanupStack::Pop(); // pop view1.

CMyViewArchAppView2* view2 = new(ELeave) CMyViewArchAppView2;

CleanupStack::PushL(view2);

view2->ConstructL();

AddViewL(view2); // Transfer ownership to CAknAppUi.

CleanupStack::Pop(); // pop view2.

SetDefaultViewL(*view1);

// More code

}

另外,视图本身并不具有绘制控件的能力,所以每个视图需要包含派生自CCoeControl和MCoeControlObserver的控件容器:

class CMyViewArchAppView1Container : public CCoeControl, MCoeControlObserver



1.4.2、Avkon视图类

每个Avkon视图类就像一个小型的AppUi。它必须提供一个Id()函数,从而系统可以标识这个视图,并且必须实现DoActivateL()和DoDeactivate()函数来完成视图激活和注销时的具体操作,此外还应该实现HandleForegroundEventL()、HandleCommandL()和HandleStatusPaneSizeChange()函数用于处理各种事件。

DoActivateL()

当视图被激活时,将调用该函数。该函数负责实例化并显示视图的控件。在视图被注销前可能多次调用该函数,所以实现该函数必须考虑重复实例化控件。

DoDeactivate()

当视图被注销时,将调用该函数,负责销毁视图中的控件。只有当应用程序退出时,或者激活同一个程序的另一个视图时,激活的视图才被注销。该函数不能异常退出。

HandleForegroundEventL()

该函数只有当视图处于激活状态下才会被调用,也就是在DoActivateL()调用之后和DoDeactivate()调用之前这段时间。当视图到达前台时,视图将接收到HandleForegroundEventL(ETrue)。当视图从前台被移除时,视图将接受到HandleForegroundEventL(EFalse)。只用视图在前台的状态实际改变时才会调用该函数。因为拥有视图的应用程序可能在前台和后台间来回切换多次,所以该函数会被调用多次。函数的实现可能用来设置焦点或控制屏幕更新。

HandleCommandL()

当视图的菜单发出消息事件时时,该函数将调用来处理菜单事件。

HandleStatusPaneSizeChange()

由于状态面板的改变导致客户区域大小的变化将调用该函数。

视图在活动期间接收事件的典型顺序:

1. DoActivateL()
2. HandleForegroundEventL(ETrue)
3. HandleForegroundEventL(EFalse)
4. DoDeactivate()

成对出现HandleForegroundEventL()可能在视图活动期间多次调用。DoActivateL()可能在DoDeactivate()调用之前多次调用。



1.4.3、视图资源(***KON_VIEW)

典型情况下,视图都需要拥有菜单项或CBA。通过将视图资源(***KON_VIEW)的ID传递给视图的BaseConstructL()方法,可以很容易为每个视图提供自己唯一的菜单项。

RESOURCE ***KON_VIEW

{
hotkeys= ;
menubar= ;
cba= ;
}



1.4.4、视图切换

本地视图切换

本地视图切换就是在同一应用程序内进行视图切换。切换时只需要指定需要切换视图的UID:

ActivateLocalViewL( TUid::Uid(1) );

外部视图切换



2、事件处理



2.1、命令(Commands)事件

命令事件是由Avkon框架产生,用来响应用户选择菜单项和系统特殊事件。AppUi或Avkon视图将会通过HandleCommandL()方法处理命令事件。



2.1.1、AppUi对命令事件的处理

在传统的应用程序架构中,AppUi的HandleCommandL()方法将处理命令事件。

void CContainerAppUi::HandleCommandL(TInt aCommand)
{
switch (aCommand)
{
case EEikCmdExit:
{
Exit();
break;
}
case ECmdXXX:
{
// implementation of cut operation
break;
}
...
default:
break;
}
}

用户自定义的命令ID(如ECmdXXX)在.hrh文件中定义,Avkon系统命令ID(如EAknSoftKeyBack)定义在avkon.hrh中。EEikCmdExit是系统标准的应用程序退出命令ID。



2.1.2、Avkon视图对命令事件的处理

在视图切换应用程序架构中,当前视图的HandleCommandL()方法将处理命令事件。

void CMyAppView1::HandleCommandL(TInt aCommand)
{
switch (aCommand)
{
case EMyAppCmdSwitchToView2:

{
AppUi()->ActivateLocalViewL(KView2Id);
break;

}
case ECmdXXX:
{
// Implement cut operation
break;
}
// ... Other view-specific command handling here
case EAknSoftkeyBack:
{
((MEikCommandObserver*)AppUi())->ProcessCommandL(EEikCmdExit);
break;
}
default:

AppUi()->HandleCommandL(aCommand);
break;
}
}



2.2、按键事件与控件栈

按键事件是用户与应用程序交互时键盘所产生的事件。键被按下时被FEP转换成相应的键事件,最终由应用程序框架传递给当前的应用程序。应用程序框架只将键事件传递给在控件栈中的对象。AppUi是缺省的键事件处理对象,但是CCoeControl派生类的UI控件应该第一时间处理键事件。因此必须将控件放入控件栈中,通常情况下由AppUi的AddToStackL()方法将控件放入控件栈中。

在传统和对话应用程序构架中,在AppUi的构造阶段(Construction()方法)将控件放入控件栈,控件将处于栈顶。当按键事件产生时,应用程序框架首先要求处于栈顶的控件处理事件,如果控件没有处理事件,那么应用程序控件将要求栈中的第二个控件处理,以此类推,当栈中的所以控件都没有处理是,将由AppUi的HandleKeyEventL()方法处理。

void CMyAppUi::ConstructL()
{
BaseConstructL();
iCurrentView = CMyAppMainView::NewL(ClientRect());
AddToStackL(iCurrentView); // to enable key events
}

在视图切换应用程序架构中,控件放入控件栈通常在视图对象的DoActivateL()中控件完成构造后进行。

void CMyView::DoActivateL(const TVwsViewId&, TUid, const TDesC8&)
{
if(!iUiControl) // iUiControl is CCoeControl-derived UI ctrl
{
iUiControl = CMyUiControl::NewL(this, ClientRect());
AppUi()->AddToStackL(*this, iUiControl); // to ctrl stack.
}
}

当不希望该控件再接收按键事件时,应该使用AppUi的RemoveFromStack()方法将控件移除控件栈。在视图切换应用程序机构中,通常在视图对象的DoDeactivate()方法中实现从栈中移除控件。

void CMyView::DoDeactivate()
{
if(iUiControl)
{
AppUi()->RemoveFromStack(iUiControl);

}
delete iUiControl;
iUiControl = NULL;
}

在控件栈中的控件响应按键事件是通过调用他们的OfferKeyEventL()方法来实现的。调用的顺序是以控件在控件栈中的顺序进行,最后放入的控件将先调用它的OfferKeyEventL()方法。OfferKeyEventL()方法必须重写,因为它的默认实现不处理任何事件。当控件处理了事件就应返回EKeyWasConsumed,因为如果返回EKeyWasNotConsumed,应用程序框架将使控件栈中的下一个控件来处理。如果所以的控件都返回EKeyWasNotConsumed,那么最后将在AppUi的HandleKeyEventL()方法中处理。

TKeyResponse CMyUiControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,

TEventCode aType)
{
TKeyResponse response = EKeyWasNotConsumed;
// pass key press events to the listbox. It will typically
// consume Up, Down, and Selection keys.
if (aType == EEventKey && iListBox)
{
response = iListBox->OfferKeyEventL(aKeyEvent, aType);
}
return response;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: