首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 操作系统 >

Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析

2013-10-08 
Symbian OS:MVC 设计模式在 SymbianOS 应用程序中的应用分析简介  MVC设计模式是在20世纪80年代发明的一种

Symbian OS:MVC 设计模式在 SymbianOS 应用程序中的应用分析

Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析
简介  
       MVC设计模式是在20世纪80年代发明的一种软件设计模式,至今已被广泛使用,后来被推荐为 Sun 公司 J2EE 平台的设计模式。 
  Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析 
  Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析 
 

MVC,model-view-control,这是一个架构模式,也是一种开发模式。

不论设计模式还是架构模式,MVC都是最经典的模式。

Symbian OS作为最热的手机开发平台之一,Symbian OS是一个微内核的系统,它应用了大量的模式进行高度模块化设计,

便于根据需求的变更和新环境进行扩展和改善适应。MVC便是其中一个模式。

回顾一下MVC的含义吧,

MVC设计模式它提供一种能够分别修改软件的不同模块的能力,提高软件的健壮性和复用性。

MVC模式能够帮助软件的设计者使用面向对象的设计原则,比如:开闭原则,通过继承而不是修改存在的基类,增加新的代码和类来扩展设计。Model:包含和操作程序中的数据,它最重要的部分是应用程序的数据结构View:定义数据模型向用户显示的方式;View传递接收到的命令和请求给controller,View是图形接口,它从Model读,并且获取需要显示的数据给用户Controller:定义用户接口对收到的命令和请求的处理,操作Model中的数据并更新View

MVC可以使得开发者根据面向对象编程的基本原则来设计他们的应用程序,开发者在实现之前必须决定应用程序的那些部分是可以扩展的哪些是不行的。设计阶段之后,代码的开发从一些基类开始,可以通过增加新的特别的类来扩展。MVC和OCP是一致的。

在Symbian S60中,MVC的使用是基于Avkon的GUI框架,框架提供基类实现Model,View和Controller。

这些类可以被应用程序设计者扩展。Avkon的基类:-CAknApplication,应用程序的基类-CAknDocument,Modle的基类-CAknAppUI,Controller的基类View的父类AVkon没有提供,但是可以从CONE环境继承。

应用程序架构(Application Framework)

 

1、S60应用程序架构

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

 

1.1、S60应用程序结构

 

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

Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析

    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)并没有区别。

Symbian OS:MVC 设计形式在 SymbianOS 应用程序中的应用分析

应用程序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:MVC 设计形式在 SymbianOS 应用程序中的应用分析

    与传统的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、视图资源(AVKON_VIEW)

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

    RESOURCE AVKON_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;     }

 

 

 

热点排行