天天看點

Symbian OS 開發初級手冊

Symbian OS 開發初級手冊 (1) Introduction

Symbian OS是目前應用最為廣泛的smart phone作業系統。 Nokia,Panasonic,Siemens,Sony Ericsson的很多手機都是基于這個系統的。 可惜國内關于Symbian OS 開發的資料實在很少。 是以我打算根據自己的(淺薄)的經驗寫一套初級教程,讓更多的人了解Symbian OS.

說起Symbian OS, 大概很多人都會想到Nokia Series 60, 80等等。 每一個symbian 聯盟手機廠商都會在純粹的Symbian OS上面添加自己的東西。 Series 60 是Nokia 的一個非常流行的軟體開發包,7650, 3650, N-gage等等都基于它。我在這裡使用的例子都可運作于Series 60. 但是我在這裡講的概念是純粹的Symbian OS 而不是series 60, 這樣的好處在于:有了這個基礎, 我們可以為任何一個使用Symbian OS 的手機開發, 而不會局限于某些Series 60等特殊的API。這樣可以使你的開發成果能夠運作于更多的裝置上。

那麼首先我們需要Series 60 SDK, 在http://www.forum.nokia.com/main/0,6566,034-4,00.html 下載下傳,安裝sdk,詳細步驟我就不在這裡描述了。 如果有什麼問題可以在這裡問我。

安裝之後,要測試基本路徑是不是設定好了。 打開一個指令行視窗,輸入 epoc , 如果你看到模拟器運作, 就說明已經安裝好了。如果沒有的話,請在提問的時候提供錯誤資訊。

有了SDK,我們就已經可以開始開發了! 但是開發環境是很重要的, 任何Symbian OS程式都要涉及多個檔案,Symbain 建議使用 Metrowork Codewarrior, 不過考慮VC6的普及程度應該更高,我在這裡使用Visual C++ 6.0. 你也可以使用VC. Net, 不過目前中文sdk不支援vc7, 你需要下載下傳英文版的。 以後指令行出現vc6的時候你就要使用vc7。

在講解我們的第一個hello world程式之前, 我要簡單說一下Symbian OS 工程的檔案結構, 我們一共需要建立4種檔案:

bld.inf 配置檔案

*.mmp 工程檔案

*.cpp 源代碼檔案

*.h 頭檔案

我們的hello world項目中, bld.inf 如下:

PRJ_MMPFILES

HelloWorld.mmp

隻有簡單的兩行, 意思是: 這個配置檔案将編譯的工程有:Helloworld.mmp. Helloworld.mmp 稍微複雜一些,暫時不在這裡講解,你隻需要知道它定義工程中都包括哪些源檔案,哪些頭檔案,哪些lib檔案就可以了。

基本的helloworld例子C:/Symbian7.0s/Series60_v21_C/examples/Basics/helloworld. 如果你的安裝路徑不同,需要相應改變。 由于實在很簡單, 這大概是所有例子中唯一沒有頭檔案的項目。Helloworld.cpp 如下:

#include "CommonFramework.h"

LOCAL_C void doExampleL()

{

_LIT(KHelloWorldText,"Hello world! ");

console->Printf(KHelloWorldText);

}

在我們講解Descriptor之前你隻需要知道_LIT把 "Hello world! "這個普通字元串轉換成了Symbian OS的字元串格式,并儲存在變量KHelloWorldText當中。 console->Printf(..)就是向指令行列印這個字元串。

那麼現在我們需要編譯這個工程,在指令行中進入examples/Basics/helloworld,輸入bldmake bldfiles, 然後abld makefile vc6, 這是建立VC工程檔案的基本步驟。 然後打開Visual studio,打開工作區, 在C:/Symbian/7.0s/Series60_v21_C/Epoc32/BUILD/SYMBIAN/7.0S/SERIES60_V21_C/EXAMPLES/BASICS/HELLOWORLD/HELLOWORLD/WINS 中。

分析一下這個巨長的路徑你會發現,其實分為4段:

1。 C:/Symbian7.0s/Series60_v21_C/Epoc32 是全局環境變量%EPOCROOT%的所在,後我們在說這個路徑的時候就用%EPOCROOT%代替。

2。build 這個目錄存放abld 生成的項目檔案。

3。SYMBIAN/7.0S/SERIES60_V21_C/EXAMPLES/BASICS/HELLOWORLD 是你的工程所在目錄。

4。HELLOWORLD/WINS 是Helloworld項目, windows 模拟器,如果你為手機編譯的話,就會是Helloworld/thumb.

然後運作的時候會彈出一個對話框要求可執行檔案。 輸入 %EPOCROOT%/release/wins/udeb/epoc.exe 然後你就會看到熟悉的"hello world"出現在s60模拟器上了!

先寫到這裡吧,但願這些文字對大家有一點用處。 下一次我将介紹Symbian OS 的基本類型 和 代碼規範

[這個blogger不能處理反斜線, 是以我隻好用 '/'代替!]

常見問題:

1。各種編譯問題

請确定你已經安裝:

visual studio 6, Active Perl, Series 60 SDK

建議VC, Series 60, 還有你以後寫的代碼都放到同一個分區下, 可以省去設定上的一些麻煩。

Symbian OS 開發初級手冊 (2)基本資料類型

Symbian OS 使用的是面向對象的C++, 但是又和标準的C++有一些差別。 比如Symbian OS沒有标準的異常處理(Exception), 因為設計Symbian OS的時候還C++還沒有把異常處理标準化。 是以Symbian設計了自己得異常處理機制: TRAP, leave. 另外就是今天要講的基本類型。 Symbian 基本上不使用任何标準的C++基本類型, 衆所周知,不同的C++編輯器對int, unsigned int的長度了解不同, 是以Symbian OS中使用 TInt8,TInt16,TInt32。

但是如果你麼沒有很好的理由是用某一特定的長度時,要使用TInt. 其他很多類型也遵守這個原則。 比如以後要講的TBuf8, TBuf16可最好用為TBuf.

類型 描述

TInt8, TUint8 8位 整數

TInt16, TUint16 16位 整數

TInt32, TUint32 32位 整數

TInt, TUint (32位)整數

TReal32, TReal64 實數

TText8, TText16 字元, 相當于 unsigned char, unsigned short int

TBool 布爾

TAny 相當于void

代碼規範

Symbian OS 使用很多代碼規範, 使用他們可以增強Symbain 代碼的可讀性, 有些規範甚至是需要嚴格遵守的, 比如類的命名:

Symbian OS的類一共有6種:

種類 例子 描述

T classes TDesC, TPoint 這個類可以向基本類型一樣使用,因為他們通常很小,而且不使用heap是以也沒有析構函數

C classes CConsoleBase, CActive 這個類是Symbian使用最多的類,C代表他們從CBase類繼承而來, 他們必須有析構函數因為他們的對象建立在heap中

R classes RFile, RTimer R代表資源(Resource),它們隻是一個系統資源的句柄,他們本身被建立在Stack上, 但是他們所使用的資源被建立在heap上,使用完畢需要Close()

M classes MEikMenuObserver 這個類是一個空的接口,使用的時候需要從它繼承

static classes User, Math 這個類隻有靜态函數, 一般都是庫函數

Structs SEikControlInfo c - struct

變量命名:

種類 例子 描述

枚舉 EMonday,ETuesday E代表枚舉

定量 KMaxFileName K代表定量

成員變量 iDevice, iX i代表成員變量

參數 aDevice, aX a代表參數

局部變量 device, x 局部變量沒有固定的規範

另外還用函數的命名, 但是要講過leave的概念後才可以了解,是以這裡先不介紹。 這一課很枯燥,但是理清了一些概念,下一課我們來仔細的看一下圖形界面的Helloworld.

Symbian OS 開發初級手冊 (3)GUI程式中的4個基本類

圖形界面的HelloWorld比文字版複雜了許多! 做過windows圖形和指令行程式的人們應該可以很容易的了解這一點。這個Helloworld一共有4個類, 他們是Symbian OS中任何圖形程式都不可少的4個基本類。他們建立了圖形界面程式的基本架構, 使得程式員們很容易就知道某些代碼應該放在什麼地方, 比如繪圖的代碼就應該放在View裡邊, 同樣當我們去讀一個程式的時候, 如果我們在意的是程式的資料結構,就該去看Document類的實作。

CExampleApplication

Application 類一共有兩個作用:第一個是設定這個應用程式的屬性, 比如UID, 每一個應用程式都有其獨特的UID. const TUid KUidHelloWorld = { 0X10008ACE };KUidHelloWorld就是這個Helloworld的UID.,AppDllUid() 向高層的架構提供這個應用程式的UID, 架構就用此來識别我們的程式。 另外就是制造一個Document類的執行個體, 是以我們隻需要兩個函數:AppDllUid 和 CreateDocument。CExampleApplication 從 CEikApplication繼承而來,很多不需要我們定義函數都被包含在CEikApplication中

CExampleDocument

Document 類是應用程式的資料模型,如果這個程式是以檔案為基礎的,它負責程式的檔案操作。 我們的Helloworl不涉及到任何檔案,但是我們仍然需要這個個類,因為它還負責制造UI類的執行個體。

CExampleAppUI

UI類盡管名字是“使用者界面“, 他并不是可視的元件,它制造View類的執行個體, 而它更重要的任務是分派指令和事件, 比如菜單指令就由UI來決定怎樣處理,配置設定到什麼類,什麼函數。 又如鍵盤事件由UI來決定分派到那個控件去處理。HandleCommandL() 這個函數就是用來處理指令的。

CExampleAppView

View 類是可視的控件, 它負責螢幕顯示,同時也可以提供相應的函數來響應相關的事件。描繪用的代碼就放在Draw函數中

這4個類的聲明都放在相應的頭檔案中, 實作在相應的cpp中,除此之外,你會發現還有一個源檔案:Helloworldbasic.cpp。 這個檔案是Helloworld的入口, 它的作用很簡單,就是建立一個Application類的執行個體。 是以大部分圖形界面的工程中這個檔案都是差不多的,隻是Application類的名字要相應改變。

這一課我們講了Symbian OS圖形程式中4個基本的類以及程式的入口。 下一課我們講Helloworldbasic中的mmp 檔案和pkg檔案。 然後我們将概述如何生成sis檔案, 也就是手機的安裝檔案。最後我們的helloworld 就可以在支援symbian 的手機上運作了!

Symbian OS 開發初級手冊 (4) mmp, pkg 檔案 和 makesis 工具

這一課我們講解mmp檔案,pkg檔案, 以及如何用makesis制作sis檔案用來安裝程式到手機上。

開始之前,有必要提一下Symbian OS程式的目錄規範, 你可以把所有頭檔案,原檔案,mmp檔案,資源檔案等都放到一個目錄下, 但是為了更有效的使用,一般把源檔案放在/src下, 頭檔案放在/inc, bld.inf,mmp檔案放在/group, sis, pkg檔案放在/sis下。

首先在group目錄中找到Helloworldbasic.mmp檔案, 它由一系列的屬性組成:

Target 這個是目标檔案名

TargetType 目标類型,也就是目标檔案的擴充名, app代表這是一個圖形界面的應用程式(application), 文字界面的那個helloworld就是exe 以後還會看到其他的擴充名如: dll, agt, prt等等

UID 這裡有兩個UID, 他們用來獨特的識别我們的程式,所有的圖形界面程式的第一個UID都是一樣的:0x100039CE, 第二個是我們的程式獨特的UID,需要從Symbian申請。 但是在開發階段可以任意使用0x01000000-0x0ffffff這個範圍. 

TargetPath 目标檔案在安裝後的路徑

SourcePath 源代碼路徑, 源代碼檔案可以存放在多個不同的目錄裡, 在編譯的時候編譯器會自動到這些目錄尋找

Source 源代碼檔案

Resource 資源檔案, 這個大概超出了本教程的範圍,因為這部教程不會詳細地将深入講解如何寫圖形程式

UserInclude 使用者頭檔案路徑, 用于存放使用者定義的頭檔案

SystemInclude 系統頭檔案路徑

Library 這些是你的程式編譯所需要的庫檔案

然後我們概述一下pkg檔案, 打開Helloworldbasic.pkg,不難看出凡是以 ';' 開頭的都是注釋, &EN代表這裡使用的語言是英語,

下面一行是應用程式資訊#{"HelloWorldBasic"}是應用程式名稱, 0x10005B91 是此程式的UID, 1,0,0是版本号.

下面這一行是你開發用的平台資訊 0x101F7960代表Series60 v2.0, "0,0,0"是尚未使用的版本号,它必須是"0,0,0", {"Series60ProductID"} 是平台資訊描述, 這個字元串将在使用者試圖安裝程式到一個不相容的平台上時出現.

再下面是安裝檔案, 左邊的是目标程式在你的機器上的路徑,右邊是裝置上的路徑,HelloWorldBasic.APP 是目标檔案, HelloWorldBasic.rsc 是編譯過的資源檔案.

有了以上的基礎,我們就可以編譯sis檔案了. 一共分為2步:

1. 進入到/group目錄下, 輸入bldmake bldfiles, 和以前講過的作用一樣, 然後: abld build thumb urel, "abld build"是編譯指令, "thumb urel"是編譯目标, 一般手機的格式都是thumb, 用指令行為windows編譯的話,就可以用 abld build wins udeb (urel). "udeb" 代表debug build, "urel"代表release build, 前者用于開發,後者用于發行。

2. 進入/sis, 輸入makesis Helloworldbasic.pkg, 然後Helloworldbasic.sis就被建立了。

下面就可以用藍牙,或者usb等通訊手段将這個sis檔案傳送到你的symbian 手機上了. 安裝,執行, 好運!:)

Symbian OS 開發初級手冊 5 - Leave

leave (不知該怎麼翻譯,就先叫離開吧) 這個詞我們在第二課提到過, 知道它是Symbain版本的異常處理。 這一課我們詳細講解它的意義和用法。 首先我們要明白為什麼要離開? 當程式運作到一個地方無法正常繼續的時候, 比如記憶體耗盡, 或者目前狀态無法進行某個操作的時候我們不能簡單的退出程式,或者忽略這些錯誤。 前者使得界面不夠友好, 而後者可能導緻不可估計的問題。 是以我們需要在這一點上離開。 讓上一層的使用我們這個函數的代碼去處理我們遇到的錯誤。 上一層代碼可以根據但是的上下環境決定該如何處理這個錯誤。

離開的基本用法:

假設我們有一個函數提取一個數組的值:

TInt GetL(TInt aIndex)

{

if(aIndex < 0 || aIndex >= KArraySize)

{

User::Leave(KErrArgument);

}

else

{

return iArray[aIndex];

}

}

要使用這個函數, 我們可以:

TInt x, err;

TRAP(err, x = GetL(5);)

if(err != KErrNone)

{

//輸出錯誤資訊等等

}

...

首先注意函數名,這是一條規範: 凡是有可能離開的函數,名稱都要以L結尾。這包括

在函數實作中使用任何形式的Leave (Leave, LeaveIfNull, LeaveIfError等等)和可leave的函數, 而又沒有TRAP掉他們的的函數。

以上的GetL函數當aIndex不在合法範圍内的時候就會leave, KErrArgument是其原因(錯誤的參數)。 使用GetL函數的時候我們可以使用TRAP宏來捕捉離開, 是以當GetL 離開的時候, 就會輸出錯誤資訊等等。 使用GetL的代碼并不一定需要TRAP隻要把他自己聲明為可離開的函數就可以, 但是要保證終歸這些函數要被TRAP掉。 圖形界面程式的架構在程式入口處提供了TRAP是以我們可以使用離開而不用TRAP一些普遍性的問題(比如記憶體不足)。但是文字程式一般需要我們自己提供TRAP.

另外還有一點就是, TRAP這個宏必須在一個CTrapCleanup的執行個體被建立以後才可以使用。 文字Helloworld中使用了頭檔案commonframework, 在Examples/basics/commonframework目錄下, 我們可以看到:

CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack

TRAPD(error,callExampleL()); // more initialization, then do example

//TRAPD是TInt error; TRAP(error,callExampleL()); 的縮寫版。

delete cleanup; // destroy clean-up stack

也就是說當你的程序中還沒有CTrapCleanup執行個體的時候, 你需要建立它才可以使用TRAP,當你不再使用TRAP的時候就删除這個執行個體。

有了離開這個基礎,我們下一課就可以講CleanupStack 和 二層構造的概念了。 之後大家就不會覺得Symbian 程式中執行個體的構造看起來很複雜了。

Symbian OS 開發初級手冊 (6) CleanupStack and Two-phase

在建立執行個體的時候Symbian C++使用 new (ELeave) 來代替普通的 new , 比如:

CBar *pBar = new (ELeave) CBar;

這個用法是考慮到手機特殊的屬性:記憶體一般較小, 經常會有記憶體不足的情況出現。 在pc上如果記憶體不足我們就會退出程式, 但是在手機不能那樣頻繁的退出, 是以記憶體不足被劃分為異常, 需要離開. 下面這個函數就會在記憶體不足的時候在A行離開:

void FooBarL()

{

CBar *pBar = new (ELeave) CBar; //A

User::LeaveIfError(pBar->Foo()); //B

delete pBar; //C

}

離開 作為異常處理的機制, 存在着一個問題。如果上面這個程式在B行Foo()傳回了一個錯誤值,就會在那一行離開,但是系統為pBar指針配置設定的記憶體也就洩漏了。為了解決這個問題, Symbian 程式中頻繁使用CleanupStack(清潔棧). 它的典型使用方式如下:

void FooBarL()

{

CBar *pBar = new (ELeave) CBar; //A

CleanupStack::PushL(pBar);

User::LeaveIfError(pBar->Foo()); //B

CleanupStack::Pop();

delete pBar; //C

}

他的作用就是, 在B行之前, 把pBar指針放到清潔棧上, 一旦B行離開了,清潔棧就會自動删除pBar回收記憶體, 如果B行順利通過, 就可以通過pop把pBar拿下來了。

CleanupStack 有效地解決了這個潛在的記憶體洩漏問題, 但是這個方法在一個特殊的情況下不适用。 那就是如果一個類的建構函數離開, 那麼new 為它配置設定的記憶體就會洩漏。 (建構的順序是:系統配置設定記憶體,然後運作建構函數)

這個問題就導入了下一個概念:two-phase construction (二層建構)

我們的目标是:建構函數在任何情況下不可以離開! 要實作它就必須:

1。 不在建構函數裡使用任何L函數

2。 不在建構函數裡配置設定記憶體

凡是需要以上兩個操作的都放到第二層建構函數中:ConstructL. 要把兩層建構結合起來,我們需要另一個靜态函數,一般為NewL或者NewLC. L大家都知道代表離開,C代表清潔棧, 下面會詳細講解NewLC的友善之處。(在這裡向大家推薦一個很不錯的英文Symbian 資料網站:http://www.newlc.com/ :)

二層建構的基本模式就是:

CHelloWorldBasicAppView* CHelloWorldBasicAppView::NewL(const TRect& aRect)

{

CHelloWorldBasicAppView* self = CHelloWorldBasicAppView::NewLC(aRect);

CleanupStack::Pop(self);

return self;

}

CHelloWorldBasicAppView* CHelloWorldBasicAppView::NewLC(const TRect& aRect)

{

CHelloWorldBasicAppView* self = new (ELeave) CHelloWorldBasicAppView;

CleanupStack::PushL(self);

self->ConstructL(aRect);

return self;

}

void CHelloWorldBasicAppView::ConstructL(const TRect& aRect)

{

// Create a window for this application view

CreateWindowL();

// Set the windows size

SetRect(aRect);

// Activate the window, which makes it ready to be drawn

ActivateL();

}

先看NewLC函數, 它建立一個CHelloWorldBasicAppView的執行個體, 然後把他放在清潔棧上,然後調用它的第二層建構函數(可以離開的), 然後并沒有把執行個體從清潔棧上取下就傳回了。這樣的好處就是如果我們用NewLC建立一個對象,然後調用它的可以離開的函數就不必把它放到清潔棧上,因為它已經在上面了。NewL的功能和NewLC 是一樣的,隻是在傳回執行個體前把它取下清潔棧。一般的C類都提供NewL,不是所有的C類都會提供NewLC.

使用清潔棧需要注意:

1. 成員變量一般不需要放在清潔棧上, 因為當執行可離開的成員函數時,它們所在的類的執行個體本身就應該放在清潔棧上。 所有的成員變量所占的資源都和此執行個體共存亡。

Symbian OS 開發初級手冊 7 Descriptors

本文簡介Descriptor。 Symbian OS 中不使用我們所熟悉的c 字元串(char*) 或者c++ 的string。 Symbian 的字元串是通過descriptor實作的。我們的第一個Symbian 程式,文字版Helloworld中是這樣使用的: _LIT(KHelloWorldText,"Hello world!n");

console->Printf(KHelloWorldText);

_LIT()是一個宏,它聲明了一個descriptor:KHelloWorldText, 其内容是"Hello world!"。下面console->Printf的參數就是一個descriptor.

Descirptor是一個靈活的設計, 它充分考慮到小型裝置的各種局限性。 為此提供了很個類,有些是可以修改的,有些是不能修改的, 有些放在stack上,有些放在heap上。 NewLC網站上有一個descriptor的結構圖:http://www.newlc.com/article.php3?id_article=12 。

其中包含了八個類, 這些并不是全部的descriptor類, 但是已經足夠我們課程目前的使用。其中TDesC是最基本的類。 其他所有的descriptor類都是由它繼承而來。 TDes是最基本的可以修改的類。凡是以C字尾的類都是不可修改的。

結構圖下面是5各最常用的descriptor類的記憶體示意圖。

TBufC<5> 中的5是它的長度, 它表示的是"NewLC"這個字元串, 是不可更改的。

TBuf<8> 8是它的最大長度, 而目前隻使用了5個位元組,它的内容是可更改的,但是注意内容長度不可以大于他的最大長度

TPtrC 是一個descriptor 指針類, 它是一個不可修改的指針, 指向不可修改的"NewLC"的位址。

TPtr 是一個可修改的descriptor指針類, 指向可修改的"NewLC"的位址。

HBufC 的H代表Heap,是專門用來在Heap上建立字元串, 其他的descriptor類的字元串一般都放在stack上。

一般來說要盡可能的使用heap記憶體, 因為stack的記憶體要更有限, 如果在stack上訪大量的字元串就很容易導緻記憶體不足。

這些類都由很多函數來使用,修改,查詢他們的字元串, 大家可以參考Developer Library中的API Reference.

_LIT()還有一個更簡單的版本, helloworld中的兩行可以改寫為:

console->Printf(_L("Hello world!n"));

Symbian OS 開發初級手冊 8 多線程

Symbian OS支援多線程, 但是用得很少, 因為官方建議盡可能使用Active Object代替。 我們将在下一課講解Active Ojbect 和推薦使用它的原因。 考慮對于

普通的程式員來說多線程是一個要熟悉的多的概念, 我們在這一課将通過一個很簡單的例子來介紹它在Symbian OS中的實作。 首先, RThread 類代表線程,我們可以通過這個類來建立,啟動,停止,關閉線程,它還包括其他一些有用的API, 大家可以參看文檔。

要建立線程RThread中一共有3 個Create函數, 基本大同小異,我們這裡就用第一個:

TInt Create(const TDesC& aName,TThreadFunction aFunction,TInt aStackSize,TInt aHeapMinSize,TInt aHeapMaxSize,TAny *aPtr,TOwnerType aType=EOwnerProcess);

aName: 線程的名稱

aFunction: 線程要執行的函數

aStackSize: 棧的大小, 一般都使用KDefaultStackSize(預設值)

aHeapMinSize: 堆的最小值

aHeapMaxSize: 堆的最大值

aPtr: aFunction的參數, 可以是任意指針

aType: 預設值為EOwnerProcess

當一個線程被建立後, 它處在非活動狀态, 要啟動它需要調用 Resume()函數。

最後, 我們要知道線程是否已經執行完畢, 有很多方法,這裡用了一個最簡單的:semaphore.

下面将介紹一個多線程的例子,因為sdk中用到多線程的例子比較複雜, 我在文字版的helloworld上建立了一個很簡單的例子。 不過你再按照本文修改

helloworld之前,建議把原本的例程做一個備份, 這樣萬一以後忘了怎麼寫helloworld也不至于去下載下傳一個新的sdk:)

這個程式建立兩個線程, 他們同時試圖修改十個整數:num, 運作的時候我們會看到num的值總是徘徊于初始值:100左右。

修改過的helloworld.cpp 在:http://homepage.ntlworld.com/jiayao/<a%20class='Channel_KeyLink'%20href='http://www.sj263.com/Article/200502/414.shtml'>Symbian</a>_Junior_Tutorial/Lesson8/helloworld.cppSymbian_Junior_Tutorial/Lesson8/helloworld.cpp

TInt ThreadFunction(TAny* aAny) 是線程要執行的函數, 它的名稱可以是任意的, 但是參數必須是(TAny* aAny). 我們可以用這個指針來傳遞任何資料, 可

以是整數,Descriptor, 數組等等。 傳回值必須是TInt. 我的實作很簡單, 它對num 進行100次改動, 根據aAny的值來定改動的方向和幅度。 每次改動之間

等待0-1秒。

下邊doExample是程式的入口, t1,t2為兩個線程,注意每一個線程建立之後的CleanupClosePushL(...), 這個是CleanupStack::PushL的延伸。 假如建立t1後我

們直接建立t2, 然後在建立t2的過程中發生錯誤,通過User::LeaveIfError(err);離開, 那麼t1所配置設定的記憶體就洩漏了。 為了避免這個情況, 我們要把t1的放

到清潔棧上。 然而記得我們第2課講的,R-class本身不動态配置設定記憶體, 他隻是系統資源的一個句柄。要回收資源就必須使用它的Close函數。

CleanupClosePushL() 就是為此情況設計的。 它把對象放在清潔棧上, 當離開發生的時候自動調用那個對象的Close函數。

然後我們建立一個Semaphore來判斷線程是否結束, 當一個線程結束時, 它會調用semaphore的Signal函數使它的值加一。

調用Resume來啟動線程。

當它的值在2你内的時候我們每1/10秒輸出一次num的值。

最後從清潔棧上取下t1,t2, 他們的Close函數會被自動調用。

Symbian OS 開發初級手冊 9 Active Object 基本概念

上課講了Symbian OS中多線程的使用, 這可我們說說Symbian OS中使用更頻繁的一個架構:Active Object(這裡簡稱AO)。

多線程在傳統程式中使用非常的廣泛, 但是在資源有限的小型裝置上卻不一定是上乘選擇。 通過上課的例程我們看到每個線程都要配置設定一定的記憶體, 如果所有的異步操作都通過多線程來做的話, 對系統是一個不小的負擔。 AO的設計就是要在同一個線程内處理異步操作。

AO 是在 ActiveScheduler (AS) 的協調下工作的, 當一個AO發出異步請求後,請求函數會立即傳回,AO可以繼續運作,或者等待。 異步操作完成後, AS會得到通知,然後它調用相應的AO中的RunL函數。 是以AO的普遍用法就是給異步操作建立一個請求函數, 然後在RunL中處理操作結果。舉例說明:我們有一個socket, 需要從網絡讀入一些資料然後輸出, 那麼我們就需要:

一個請求函數:

void MyA:RequestReceive()

{

iSocket.Recv(iBuf,...,iStatus);

}

和RunL:

void MyA:RunL()

{

iConsole->Printf(iBuf);

}

使用此AO的時候, 就可以先調用RequestReceive()然後繼續做其他的事情, 當socket讀入完畢後AS會調用這個AO的RunL,那麼接受的資料就會被列印出來了。當然,要實際在程式中使用AO我們還需要學習很多東西。到此你隻需要對AO有個概念上的了解。

以下是在NewLC轉過來的一個圖示, 基本勾畫出了Active Object的架構:

Symbian OS 開發初級手冊

今天先說到這裡, 因為現在比放假的時候忙了許多, 沒有時間大塊的寫文章了。 隻能每次寫一小段, 這樣一些比較大的話題就要分n課來說了。 

繼續閱讀