`
love19820823
  • 浏览: 934290 次
文章分类
社区版块
存档分类
最新评论

Symbian应用程序的启动过程

 
阅读更多

考虑到Symbian作为一个商业的开放操作系统,它的UI框架结构和功能必须达到易用、强大和可靠的统一,不是简简单单完成人机交互而已。所以它的结构必须是经过精心设计的。因此,要想详细描述其内在的运行过程,一般方法是通过自顶向下并逐步分解来详细介绍。但这同时也存在一个缺点,就是容易忽视各种模块之间的交互过程。所以本文将以一个应用程序启动、运行和结束这样一个流程将UI的整体框架串接起来,相信这样可以更容易理解。当然读者最好已经熟悉 Symbian应用程序框架,要知道什么是The UI Control Framework (CONE)以及Application Architecture (APPARC),这样理解起其内在机制更容易一些。

我们先看一个应用程序的入口函数:

LOCAL_C CApaApplication* NewApplication()

{

return new CXXXApplication;

}

GLDEF_C TInt E32Main()

{

return EikStart::RunApplication( NewApplication );

}

可以看出,在E32Main()函数中,调用了EikStart::RunApplication( NewApplication )函数,该函数的参数是指向NewApplication函数的指针。

我们先看EikStart中RunApplication函数的声明

IMPORT_C static TInt RunApplication(TApaApplicationFactory aApplicationFactory)

这里有一个工厂类TApaApplicationFactory,该类可以看作是建立应用程序的工厂。在E32Main()函数中,调用的是EikStart::RunApplication( NewApplication )函数,参数是指向NewApplication函数的指针。那和TApaApplicationFactory有什么关系呢?我们看看apparc.h中TApaApplicationFactory的定义:

class TApaApplicationFactory

{

public:

typedef CApaApplication* (*TFunction)();

public:

IMPORT_C TApaApplicationFactory(TFunction aFunction);

……

原来在调用EikStart::RunApplication过程中,编译器创建一个TApaApplicationFactory对象,以指向 NewApplication函数的指针为TApaApplicationFactory构造函数的参数。即编译器调用IMPORT_C TApaApplicationFactory(TFunction aFunction)作为TApaApplicationFactory的构造函数。

好,TApaApplicationFactory对象已经创建了,我们现在深入IMPORT_C static TInt RunApplication(TApaApplicationFactory aApplicationFactory)函数,来看看它是如何启动并运行UI程序的。

TInt err = KErrNoMemory;

CEikonEnv* coe = new CEikonEnv;

这是RunApplication函数最先执行的代码,很简单,它在堆上创建了一个CEikonEnv对象,了解Symbian的都知道。这个对象是Symbian UI框架中CONE的基础。既然它又是第一个被调用的UI框架组件,我们必须对它的功能有一个详细的了解。


CEikonEnv继承于CCoeEnv,而CCoeEnv则继承于CActive,从这里可以看出CEikonEnv就是一个以事件驱动为基础的异步调用操作,这在后面还会介绍。

在CEikonEnv* coe = new CEikonEnv中,CEikonEnv的构造函数里执行了这样的代码:

EXPORT_C CCoeEnv():CActive(EActivePriorityWsEvents)

{

……

iCleanup = CTrapCleanup:New()

……

}

可以看到它装载了清除栈,那么从现在开始清除栈就可以使用了。接下来它又执行了下面一段代码:

If(coe != NULL)

{

TRAP(err, coe->ConstructAppFromCommandLineL(

aApplicationFactory, *aCommandLine));

}

顾名思义,该函数负责整个application框架的初始化工作,具体细节在这里不一定介绍,主要强调过程及如何与底层相互衔接。对于初始化这部分工作,CEikonEnv 主要是通过在该函数内调用基类的CCoeEnv::ConstructL,那我们来看看它主要完成了哪些工作:

u 创建Active Scheduler,将自身作为Active Object加入到Active Schelduler

u 创建与Window Server的连接RWsSession

u 创建RWindowGroup,作为应用程序的根窗口

u 创建CWsScreenDevice对象

u 创建CWindowGc对象

下面我们一一介绍每一步骤的功能:

1) 创建Active Scheduler

该函数首先创建了Active Scheduler,将自身作为Active Object加入到Active Schelduler,这样CEikonEnv就可以异步的负责处理从Window Server来的标准事件(如键盘或是触摸屏事件)和重绘事件。但是Active Scheduler在这里还没有被启动,所以暂时还没有事件被处理。

2) 创建Window Server的连接

Window Server是UI处理的核心组件,它采用的是标准SymbianC/S模式,其主要功能有:

a) 处理键盘、触摸屏事件及窗口绘制事件,并将它发到相应的客户端的请求代码。

b) 负责SymbianUI的窗口绘制和管理,采用树形结构。包括窗口的建立,刷新和销毁。

c) 提供客户调用API:RWsSession,并提供其它相应的插件以方便用户扩展,例如Animation、Sprites和Cursor。

CEikonEnv通过定义Window Server的客户类的成员变量RWsSession来与Window Server进行通信。其初始化过程便在这里执行。

3) 初始化RWindowGroup

RwindwoGroup是用来在Window Server内创建窗口组(window group)的,窗口组是一种特定的不能被显示的Window,它仅作为应用程序的根窗口。且键盘和事件的焦点和它联系在一起,这样的话Window Server就知道已经有一个应用程序已经和它产生联系,需要在适当的时候将按键等事件发给应用程序

4) 创建一个与文件服务的RFs连接以便于读取资源文件。例如,RSS文件。

5) 创建图形上下文一个是CWsScreenDevice,另一个是CWindowGc。

Window Server无法负责具体的应用程序屏幕绘制功能,而是应由应用程序间接的控制Window Server来绘制图形。所以这里有两个类,作为CEikonEnv的成员函数提供给应用程序来完成它的图形会制功能,一个是 CWsScreenDevice,另一个是CWindowGc。CWsScreenDevice实际上是一个虚拟的屏幕设备,储存着屏幕的大小及各种参数。CWindowGc是用来提供窗口绘图环境,比较常见。具体可以参考Symbian SDK。

完成初始化之后,会执行如下函数:

CEikDocument* const doc = STATC_CAST(CEikDocument*, iProcess-> AddNewDocumentL(aApplicationFactory));

这段代码最终创建了CApaApplication和Document及整个应用程序框架,我们来看看到底如何创建的,首先 AddNewDocumentL的参数是TApaApplicationFactory,该对象前面已经讲过是如何创建的,于是在 AddNewDocumentL中首先会执行如下函数:

CApaApplication* TApaApplicationFactory::CreateApplicationL() const

{

CApaApplication* application = NULL;

……

// create application

Application = (*reinterpret_cast(iData))();

}

其中TFunction的定义前面已经讲过,也就是说在应用程序中的定义的NewApplicaion函数在这里终于被执行到了, CApaApplication子类的对象已经创建。接下来继续调用CApaApplication的CreateDocumentL函数就可以创建 CApaDocument子类的对象。在CApaDocument子类的对象被创建好以后,会接着调用CEikAppUi* CEikDocument::CreateAppUiL()函数,这个函数是纯虚函数,是应用程序提供用来建立CEikAppUi对象的。

接下来,被创建的CEikAppUi对象会初始化对View Server的连接并建立相应的视图,这在多视图应用程序中会被用到。

1.1.2. Symbian应用程序的运行过程

好,我们再回到EikStart::RunApplication,在TRAP(err, coe->ConstructAppFromCommandLineL(aApplicationFactory, *aCommandLine))后会执行这样一段代码。

Coe->Execute();

该函数是这样的:

TRAPD(exitCondition, CActiveScheduler::Start());

这时候Active Scheduler被启动了,CEikonEnv作为CActive的子类,就不断的开始响应Window Server传来的事件。于是整个应用程序就开始真正的工作了。我们来看看具体的运行过程。

如果了解Symbian应用程序结构,就知道CEikonEnv只是应用程序和Symbian UI资源交互的一个桥梁或环境,属于CONE,本身并不具体处理应用程序的逻辑。它只是建立应用程序运行环境并不停的从Window Server去获取该应用程序的事件。它将事件还是交给APPARC来处理,所以我们需要结合APPARC和CONE来说明。

首先,注意到CEikonEnv继承于CActive,自然我们就需要知道RunL函数是怎么工作的,

EXPORT_C void CCoeEnv::RunL()

{

Switch (iStatus.Int());

{

Case KErrNone:

break;

……

TWsEvent event;

iWsSession.GetEvent(event);

const TUint handle = event.Handle();

if (handle)

{

CCoeControl* const window = IsHandleValid(handle)?REINT ERPRET_CAST(CCoeControl*, handle):NULL;

iLastEvent= event;

iAppUi->MonitorWsEvent(event);

iAppUi->HandleWsEventL(event, window);

}

}

RunL从Window Server取出TWsEvent事件,并对其调用iAppUi->HandleWsEventL(event, window), iAppUi的类定义是CEikAppUi,即APPARC中一个非常重要的UI类,负责所有与UI相关的工作。它的HandleWsEventL就会去处理来自于Window Server的事件。

那么HandleWsEventL中又是如何处理的,我们以Keydown事件为例:

EXPORT_C void CCoeAppUi::HandleWsEventL(const TWsEvent&aEvent,CCoeControl* aDestination)

{

Tint type = aEvent.Type();

switch(type)

{

……

Case EEventKeydown:

If(iStack->OfferKeyL(*aEvent.Key(), (TEventCode)type)==EKeyWasNotConsumed)

HandleKeyEventL(*aEvent.Key(), (TEventCode)type);

……

}

……

}

首先我们来看iStack,iStack的类定义是CCoeControlStack,该堆栈存储了所有属于此应用程序的CCoeControl,当 CEikonEnv拿到Window Server与该应用程序相关的事件时,会调用CEikAppUi基类CCoeAppUi的HandleWsEventL函数。对于Keydown事件,如果iStack中的CCoeControl没有消耗掉该Keydown事件,就会调用CEikAppUi基类的CCoeAppUi 的虚函数HandleKeyEventL(*aEvent.Key(), (TEventCode)type),这个虚函数经常被实际应用程序重写。通过这个实例,我们就可以大概了解Symbian应用程序的运行过程。

最后我们还需要知道如何订阅Window Server的事件,否则CEikonEnv这个Active Object无法进行异步调用。它是在CActiveScheduler里进行Window Server事件的订阅,CONE采用的Active Scheduler不是标准的CActiveScheduler,是继承于CActiveScheduler的扩展CCoeScheduler,它重写了WaitForAnyRequest函数:

EXPORT_C void CCoeScheduler::WaitForAnyRequest();

{

iCoeEnv->ReadEvent();

User::WaitForAnyRequest();

}

可以看到,CCoeScheduler的不同之处在于在等待其它线程唤醒时,一定要执行iCoeEnv->ReadEvent()这个函数,它的内部实现是一个异步函数,订阅了来自于Window Server的事件。这样有事件从Window Server过来就会执行CEikonEnv的RunL函数,执行完当CActiveScheduler进行WaitForAnyRequest等待时,就会再次向Window Server订阅事件,So on and so forth
<link title="RSS" href="http://fuyinshitu.blog.163.com/rss/" type="application/rss+xml" rel="alternate">
<script language="JavaScript"> function initUD(){ UD.body=$("_$$_inner_layer"); UD.layer=$("_$$_outer_layer"); UD.window=$("blog-163-com-body"); UD.bar=$("theme_selector_pointer"); } </script><script language="JavaScript"> // <![CDATA[ var g_urlPrefix=""; function g_initCommon(){ var _arr = ["rmdtpxt","rmdtplgn"]; for (var i=_arr.length-1;i>=0;i--){ _o = $(_arr[i]); if(i==0)_o && (_o.onclick=function(){exitAfterLogged();return false;}); else if(i==1)_o && (_o.onclick=function(){showLoginDlg('fuyinshitu.blog.163.com');return false;}); } topFromUrsLogin(); } function g_initUtil(){ TopSearch.init(); } // ]]> </script><style type="text/css"> <!--/*--><![CDATA[/*><!--*/ #messageZone {top:0px; right:20px; background:#ffffae; width:100px; position:fixed!important; position:absolute;font-family: Arial,Helvetica,sans-serif; padding:4px;font-size:12px;} /*]]>*/--> </style> <script src="http://st.blog.163.com/js/utils/InfoAlertPad.js" type="text/javascript"></script><script language="javascript"> function initAll(){ try{ initUD(); g_initCommon(); initFlash(1); showPageTopBar({serverName:'fuyinshitu.blog.163.com',serverHostName:'blog.163.com'}); initPage(); window.setTimeout("g_initUtil();",3000); }catch(e){} } initAll(); </script><script language="JavaScript"> function onVisitorInfoLoad(_p){ var _s = $('visitorInfoJs').readyState; if (_p && _s!='loaded'&&_s!='complete') return; gLoadPermaLink(1, 'prev', 'fks_084074086087088074086087095095083082089067084082094070', 20, -100, 'Symbian应用程序的启动过程', 'blog/static/74800485200862310245913', '74800485200862310245913', 'http://q.163.com', 0, 1, 'off' ); topFromUrsLogin(); } var ver = new Date().getTime(); document.write('<script type="text/javascript" onreadystatechange="onVisitorInfoLoad(true);" onload="onVisitorInfoLoad();" id="visitorInfoJs" src="http://blog.163.com/js/static/visitorInfo.js?host=fuyinshitu&mode=prev&channel=blog&blogId=fks_084074086087088074086087095095083082089067084082094070&pubTime=1216779845913&v=' + ver + '"></'+'script>'); </script><script id="visitorInfoJs" onreadystatechange="onVisitorInfoLoad(true);" src="http://blog.163.com/js/static/visitorInfo.js?host=fuyinshitu&amp;mode=prev&amp;channel=blog&amp;blogId=fks_084074086087088074086087095095083082089067084082094070&amp;pubTime=1216779845913&amp;v=1229489686421" type="text/javascript" onload="onVisitorInfoLoad();"></script>
分享到:
评论

相关推荐

    Symbian应用程序运行框架

    所以本文将以一个应用程序启动、运行和结束这样一个流程将UI的整体框架串接起来,相信这样可以更容易理解。当然读者最好已经熟悉 Symbian应用程序框架,要知道什么是The UI Control Framework (CONE)以及Application...

    Symbian UI 设计基础

    (1)核心应用程序类. 所有的S60 UI应用程序都具有一些基本功能: ◆提供一个用户界面,用于显示信息并允许用户进行交互 ◆响应各种用户启动的事件,比如用户选择一个菜单项 ◆响应系统启动的不同事件,比如导致屏幕...

    Android程序设计基础

    一个应用程序的组件可以在另一个应用程序中用作其他用途。你甚至可以将Android内置的组件替换为自己改进后的版本。这将在移动领域掀起新一轮的创造风潮。  众多开箱即用的内置服务。基于位置的服务使用GPS或手机...

    Android应用开发详解pdf.pdf

     第一篇 基础篇第1章 Android概述Android概述,讲述了Android的前生后世、架构和特点、Android Market、应用程序组件和Android与Java ME的区别及联系  第2章 Android开发基础Android开发基础,讲述了Android开发...

     一.JAVA程序传送到手机的方法:

     通过手机上网下载以及使用短信定购的方式,直接在手机的个人文档或者应用程序中找 到(根据手机各不相同),无需在安装,直接可以在类似"我的文件夹"之类的选项找到。  使用电脑下载就需要将文件传送到手机上。 ...

    搜狗手机助手 v2.8.0.28817 官方版.zip

    3.应用管理:手机接入后能识别手机中已安装的应用程序,并提供安装、卸载和升级的功能。 4.手机连接到搜狗手机助手应用中心,提供免费应用推荐和应用下载。 5.联系人:手机接入后能读取手机中的联系人信息。   ...

    Symbian OS C++高效编程

    797.6 动态缓冲区 807.7 小结 82第8章 使用活动对象的事件驱动多任务 848.1 多任务基础 848.2 事件驱动多任务 858.3 使用活动对象 878.4 示例代码 908.5 没有活动调度器的线程 938.6 应用程序代码...

    嵌入式系统/ARM技术中的一种多级启动的Boot Loader设计方案

     OMAP(开放式多媒体应用平台)是TI公司推出的一款面向多操作系统(包括PalmOS5.0,PocketPC2002和通信领域的Symbian)的高性能低功耗处理器。它集成了包括一个数字协处理器在内的多媒体单元,并且加入GSM/GPRS接口...

    ESET Mobile Security 的安装教程.pdf

    1.2   安装 安装前保存所有打开的文档并退出所有运行的应用程序。您可以在设备上直接安装 ESET Mobile Security 或使用计算机来安装它。 成功安装后,通过遵循 产品激活部分中的步骤激活 ESET Mobile ...

    新版Android开发教程.rar

    Android 是一个专门针对移动设备的软件集,它包括一个操作系统,中间件和一些重要的应用程序。 Beta 版 的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 ...

    AppCan-BBS v2.2 for Discuz!X2 和 Discuz!X2.5.rar

    9. 启动应用自动开启wifi 10. 应用不提示自动更新 11. 一直处于加载状态 12. 待审核的帖子依旧显示问题 13. 加密相册访问限制问题 14. 设置权限后未生效的问题 15. 个人头像上传无法替换问题 16. 部分手机...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Activity Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务,是一个负责与用户交互的组件 SSH 为 Struts+Spring+Hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架。...

    tengge py for s60编程教程

    3.2启动程序和程序列表 3.3对列表操作的函数 3.4随机选择和随机数 3.5图像保存和处理 3.6绑定快捷键 3.7网页源码查看器 3.8联网提交数据 3.9对文件的操作 4.0制作一个截图软件 4.1局部变量和全局变量 4.2资源管理器...

    Android智能手机调研报告.doc

    应用程序自动随着手机旋转 ·短信、Gmail、日暦,浏览器的用户接口大幅改进,如Gmail可以批量删除邮件 ·相机启动速度加快,拍摄图片可以直接上传到Picasa ·来电照片显示 3) Android 1.6 代表机型HTC Hero G3 在...

    贝岭的matlab的代码-nfccorkboard:使用NFC功能扩展QtSDK的QtQuickcorkboards示例:触摸标签,其NDEF

    的记录的标签时,应用程序会自动启动。 C++ 类封装了 NFC 功能,并在运行时向用户界面的 QML 文件注册。 这允许使用信号和插槽在 UI 和 NFC 引擎之间进行直接和轻松的通信:在 QML 中创建一个 NdefManager 元素并对...

    贝岭的matlab的代码-nfccreator:基于JavaME的NFCCreator可以将许多不同的NFC论坛NDEF消息格式写入所有支持的

    应用程序检查设备的 NFC 可用性。 目前支持以下消息类型进行写入: 带有 URI、标题*、动作* 和图像* 的智能海报(* 可选) URI 记录,使用所有定义的 URI 缩写自动编码。 文字记录; 可以在源代码中调整默认的英语...

    wince的GPS模拟器

    句,通过串行口输出到GPS应用软件。用鼠标或键盘控制Virace而模拟实际GPS接 收器的运动,或者重播已有的GPS航迹文件,从而在室内测试GPS导航软件等。 Virace具有手动实时控制及航迹重播两种方式。为了控制灵活方便...

Global site tag (gtag.js) - Google Analytics