BREW應(yīng)用程序的模型是基于一個事件驅(qū)動的協(xié)作式多任務(wù)模型。事件處理機(jī)制的核心問題是程序應(yīng)該只處理需要的事件,對于不需要處理的事件,需要返回給系統(tǒng)處理。應(yīng)用在加載之后可以通過 HandleEvent()函數(shù)接收所有輸入的事件,然后會通過返回TRUE(已處理)或FALSE(未處理)指示是否處理事件。AEE層存在一個全局的事件隊(duì)列,所有的事件都存儲在該隊(duì)列中,如果隊(duì)列中的事件在分發(fā)后處理完畢或者無人處理,該事件將被從事件隊(duì)列中刪除。

BREW中的事件主要有三類:系統(tǒng)事件,預(yù)定義的事件和自定義的事件。系統(tǒng)事件的事件代碼范圍為0~7,即從EVT_APP_START 到 EVT_APP_BROWSE_FILE。預(yù)定義事件的事件代碼范圍是0x0008-0x4fff,即BREW AEE 層和OEM層預(yù)定義或者預(yù)留的事件。自定義的事件是指 BREW應(yīng)用可以自定義自己的事件,自定義事件應(yīng)該不小于EVT_USER(0x5000)。BREW應(yīng)用可以發(fā)送任何事件給應(yīng)用自身,或者發(fā)給在同一進(jìn)程中的其他應(yīng)用。如果發(fā)送事件給不同進(jìn)程的應(yīng)用(主要是針對BREW 4.X及以上版本),這時(shí)需要特殊的應(yīng)用權(quán)限。

BREW環(huán)境要求及時(shí)地處理事件。簡而言之,如果應(yīng)用執(zhí)行處理事件HandleEvent()調(diào)用后沒能在合適的時(shí)間返回,AEE可能就會關(guān)閉應(yīng)用以保護(hù)設(shè)備相應(yīng)其他請求。有些操作,比如說從網(wǎng)絡(luò)套接字中讀取數(shù)據(jù),也許耗時(shí)過長,無法在一次調(diào)用事件處理器內(nèi)完成。這時(shí)就采用回調(diào)機(jī)制,以便在操作完成之后通知該應(yīng)用。

4.3.2.1事件處理器

AEE執(zhí)行環(huán)境調(diào)用BREW 應(yīng)用自身的事件處理器來傳遞關(guān)于一系列事件的消息。有過windows編程經(jīng)歷的讀者都會清楚這種機(jī)制,Windows下消息處理機(jī)制:當(dāng)在交互中進(jìn)行一個操作(信號,輸入,等等),windows將產(chǎn)生相應(yīng)的事件,通過window的事件分發(fā)機(jī)制,相應(yīng)的窗口或者應(yīng)用得到該事件,從而觸發(fā)相應(yīng)的事件處理器進(jìn)行處理。BREW中事件處理機(jī)制與其相似,即BREW環(huán)境捕捉到事件后,分發(fā)到相應(yīng)的應(yīng)用或者控件,由應(yīng)用或者控件的事件處理器進(jìn)行處理。

以下是BREW中事件處理器接口的示例:

?????? boolean MyApp_HandleEvent(IApplet * pIApp,

?????? AEEEvent eCode,

?????? uint16 wParam,

?????? uint32 wParam)

在該示例中,變量pIApp實(shí)際上指明了應(yīng)用的結(jié)構(gòu),也就是AEEApplet的一個指針。許多應(yīng)用將其結(jié)構(gòu)定義為AEEApplet的超集,而pIApp也能指向該結(jié)構(gòu)。

eCode變量是說明應(yīng)用接收的事件類型,如EVT_APP_START、EVT_KEY和EVT_ALARM等典型事件。

wParam和dwParam參數(shù)是依據(jù)接收的事件而定義的短數(shù)據(jù)和長數(shù)據(jù)值。這些值取決于事件本身,根據(jù)事件自身來定義。對于某些事件,短數(shù)據(jù)和長數(shù)據(jù)字段中都包含事件數(shù)據(jù);而對于另一些事件,長短字段中僅有一個字段,甚至沒有字段。兩個數(shù)據(jù)字段均不包含數(shù)據(jù)的事件有EVT_APP_START、EVT_APP_STOP、EVT_APP_SUSPEND和EVT_APP_RESUME。兩個數(shù)據(jù)字段中都包含數(shù)據(jù)的典型事件有EVT_DIALOG_START和EVT_COMMAND。僅在短數(shù)據(jù)字段中包含數(shù)據(jù)的典型事件有EVT_ALARM,僅在長數(shù)據(jù)字段中包含數(shù)據(jù)的典型事件有EVT_NET_STATUS和EVT_CTL_CHANGING。

按鍵事件作為EVT_KEY 事件發(fā)送給應(yīng)用。短數(shù)據(jù)字段包含主鍵代碼;比如說如果用戶按下按鍵符合“2”,就包含AVK_2這一主鍵代碼。AVK_2的值由AEEVCodes.h頭文件定義。

在Emulator中,與按鍵符號相對應(yīng)的主鍵代碼由設(shè)備配置文件確定,也可經(jīng)由設(shè)備配置器進(jìn)行修改。在手機(jī)上,主鍵代碼由設(shè)備廠商決定。

4.3.2.2事件處理的提示

執(zhí)行應(yīng)用時(shí),僅考慮處理應(yīng)用可能需要處理的事件。許多事件可以被忽略。舉例來說,如果執(zhí)行一個游戲應(yīng)用時(shí),僅需使用上下左右箭頭鍵,則可忽略接收到的0-9按鍵事件。

但是如果接收到關(guān)鍵事件,則無論應(yīng)用處于何種狀態(tài)都不能忽略。如EVT_START、 EVT_STOP、EVT_SUSPEND和EVT_RESUME等系統(tǒng)事件就是在任何情況下都會影響應(yīng)用的例子,所以不能忽略。需要特別注意的是,無論應(yīng)用給定狀態(tài)如何,必須接收所有的關(guān)鍵事件。某些事件在應(yīng)用特別指示需要此類通知時(shí)才會發(fā)送。應(yīng)用必須為這些通知事件注冊,可以在MIF編輯器中指定MIF文件的通知事件注冊,或者使用ISHELL_RegisterNotify()進(jìn)行動態(tài)注冊。

作為一個約定,應(yīng)用在處理EVT_START分配的任何數(shù)據(jù),在處理EVT_STOP時(shí)都應(yīng)該釋放出去。但是,在AEEClsCreateInstance()中分配的內(nèi)存數(shù)據(jù),一般必須通過FreeAppData()機(jī)制來釋放。

4.3.2.3事件分發(fā)與代理

當(dāng)控件激活時(shí),事件應(yīng)該傳遞到激活的控件,使控件進(jìn)行自我更新,又叫做事件代理。例如,如果菜單控件處于激活狀態(tài),應(yīng)該將事件傳遞到IMENUCTL_HandleEvent();如果文本控件處于激活上,應(yīng)傳遞到ITEXTCTL_HandleEvent(),然后控件就會采取相應(yīng)的操作。以菜單控件來說,它就會改變被選項(xiàng)目,重新繪制菜單。

正如事件處理函數(shù)將TRUE或FALSE返回AEE執(zhí)行環(huán)境那樣,控件返回TRUE或FALSE則表示它們處理的事件。每個控件類型只會處理必要的事件。標(biāo)準(zhǔn)菜單控件只處理“上”、“下”和其他部分關(guān)鍵事件,而軟鍵菜單控件則處理“左“、“右”和其他關(guān)鍵事件。如果一個控件從發(fā)放的事件中返回的是TRUE,應(yīng)用就可以早一點(diǎn)從事件處理函數(shù)中退出來,但還可以執(zhí)行額外的處理。如果一個控件從發(fā)放的事件中返回的是FALSE,應(yīng)用一般應(yīng)該繼續(xù)處理該事件。如果該控件接收的是從事件處理器返回的FALSE,BREW就要執(zhí)行默認(rèn)的處理。

當(dāng)用戶按下“選擇”鍵進(jìn)行選擇時(shí),菜單控件使用EVT_COMMAND來通知應(yīng)用。在這種情況下,一個來自“選擇”鍵下放的EVT_KEY按鍵事件就由菜單控件處理。此外,對于菜單控件任何視圖更新,菜單控件將EVT_COMMAND事件發(fā)回給應(yīng)用。事實(shí)上,所有控件類型都能提供代理機(jī)制。

AEE?? Shell

?

My App

?

IMenuCtl

?

?

?

?

?

?

?

?

?

所有的事件

?

按鍵事件

?

?

?

Ture /False

?

Ture /False

?

圖 4-7: BREW中的事件分發(fā)示例

?

?????? 事件的分發(fā)代理機(jī)制非常靈活,你可以在消息循環(huán)中按照你的需要自由處理(圖。

用戶按下某一個鍵

?

與該鍵相關(guān)的事件被傳送

給您的事件處理函數(shù)

?

可以將它交給

IMENUCTL_HandleEvent()

?

可以選擇先處理它

?

也可以再次處理它

?

圖 4-8: BREW中的事件代理機(jī)制

?????? BREW下的消息處理機(jī)制與Windows下的消息處理機(jī)制的區(qū)別在于:BREW的體系結(jié)構(gòu)采用了COM方式,即具有面向?qū)ο蟮念悓哟谓Y(jié)構(gòu),從而其具體的事件處理機(jī)制也是作為各個接口外露的接口函數(shù)的形式被運(yùn)用。一個應(yīng)用本質(zhì)上來說就是一個實(shí)例化的IAPPLET類,所以這樣就統(tǒng)一了所有在應(yīng)用中運(yùn)用的事件處理機(jī)制都是各個接口外露接口函數(shù)的說法。具體而言,這些事件處理器還是有區(qū)別的,主要是IAPPLET_HandleEvent和其他接口的HandleEvent的區(qū)別。

?????? IAPPLET_Handleevent是通過在AEEClsCreateInstance中的AEEApplet_New函數(shù)被注冊實(shí)例化的,AEEApplet_New函數(shù)實(shí)例化應(yīng)用同時(shí)也通過傳入U(xiǎn)SERAPP_HandleEvent參數(shù)實(shí)例化了IAPPLET_Handleevent。

?????? 除了IAPPLET具有handleevent外,所有的繼承IControl的接口也具有事件處理函數(shù),允許處理事件。這些各種具體的IControl_handleEvent有兩種方式被調(diào)用。一種是在應(yīng)用的handleevent中由開發(fā)者顯式的調(diào)用,如:

switch (eCode)

{

??? case EVT_APP_START:????????????????????????????

???? return(TRUE);

??? case EVT_APP_STOP:????

……….

??????? Case EVT_KEY:

IMENU_Handleevent….

ItextCtl_Handleevent….

}

另一種是當(dāng)這些控件包含于對話框中,且處于聚焦?fàn)顟B(tài)時(shí),這些事件處理函數(shù)的觸發(fā)是隱式的,是由AEE機(jī)制自動觸發(fā)的,無需在代碼中顯式的調(diào)用這些handleevent。 IDialog接口沒有外露的handleevent接口函數(shù),但是允許通過IDialog_seteventhandle來注冊一個該對話框的事件處理函數(shù)。需要注意的是該事件處理函數(shù)是何時(shí)被觸發(fā)的:一旦當(dāng)一個對話框處于激活時(shí),AEE層將會把所有的事件直接發(fā)往該對話框,該對話框會自動的調(diào)用處于焦點(diǎn)控件的handleevent來處理該事件,只有當(dāng)該控件沒有處理該事件時(shí),對話框注冊的事件處理函數(shù)才會被調(diào)用。

當(dāng)BREW運(yùn)行后,首先操作系統(tǒng)中的ui 任務(wù)會捕捉到各種事件,此時(shí)ui 任務(wù)通過aee_dispatch將事件分發(fā)至BREW環(huán)境中。BREW環(huán)境再通過aee_sentevent具體分發(fā)事件至目的地,在兩種不同的情況下將走不同的流程。

?????? 如果當(dāng)前沒有激活的對話框,則緊接著IAPPLET_Handleevent被BREW自動調(diào)用來處理事件,而此時(shí)調(diào)用的IAPPLET_Handleevent其實(shí)就是用戶注冊的app_handleevent。從而實(shí)現(xiàn)了允許用戶的應(yīng)用捕捉到事件并處理的機(jī)制。在用戶的app_handleevent中,用戶可以將事件繼續(xù)下發(fā),比如通過調(diào)用IMENU_handleevent等將事件下發(fā)給各種控件處理。

如果當(dāng)前有激活的對話框,則基于對話框的事件被BREW自動調(diào)用,從而使得事件被對話框最先截獲,而對話框之后的處理是檢查包含的控件中哪個處于焦點(diǎn),并將事件下發(fā)給它的handleevent來處理,同時(shí)根據(jù)其返回值來判斷其是否已經(jīng)處理了該事件,當(dāng)其返回False后,對話框?qū)⒃撌录^續(xù)轉(zhuǎn)發(fā)至該對話框注冊的handleevent(如果有的話),如果該handleevent仍然返回false,BREW繼續(xù)將該事件轉(zhuǎn)發(fā)至app_handleevent。這種機(jī)制使得當(dāng)以對話框方式來創(chuàng)建應(yīng)用時(shí),各種事件被自動的處理,從而簡化了代碼量,但也使得事件流程更加晦澀,用戶的應(yīng)用程序不能直接的控制它。

?