BREW應用程序的模型是基于一個事件驅(qū)動的協(xié)作式多任務模型。事件處理機制的核心問題是程序應該只處理需要的事件,對于不需要處理的事件,需要返回給系統(tǒng)處理。應用在加載之后可以通過 HandleEvent()函數(shù)接收所有輸入的事件,然后會通過返回TRUE(已處理)或FALSE(未處理)指示是否處理事件。AEE層存在一個全局的事件隊列,所有的事件都存儲在該隊列中,如果隊列中的事件在分發(fā)后處理完畢或者無人處理,該事件將被從事件隊列中刪除。
BREW中的事件主要有三類:系統(tǒng)事件,預定義的事件和自定義的事件。系統(tǒng)事件的事件代碼范圍為0~7,即從EVT_APP_START 到 EVT_APP_BROWSE_FILE。預定義事件的事件代碼范圍是0x0008-0x4fff,即BREW AEE 層和OEM層預定義或者預留的事件。自定義的事件是指 BREW應用可以自定義自己的事件,自定義事件應該不小于EVT_USER(0x5000)。BREW應用可以發(fā)送任何事件給應用自身,或者發(fā)給在同一進程中的其他應用。如果發(fā)送事件給不同進程的應用(主要是針對BREW 4.X及以上版本),這時需要特殊的應用權(quán)限。
BREW環(huán)境要求及時地處理事件。簡而言之,如果應用執(zhí)行處理事件HandleEvent()調(diào)用后沒能在合適的時間返回,AEE可能就會關(guān)閉應用以保護設備相應其他請求。有些操作,比如說從網(wǎng)絡套接字中讀取數(shù)據(jù),也許耗時過長,無法在一次調(diào)用事件處理器內(nèi)完成。這時就采用回調(diào)機制,以便在操作完成之后通知該應用。
4.3.2.1事件處理器
AEE執(zhí)行環(huán)境調(diào)用BREW 應用自身的事件處理器來傳遞關(guān)于一系列事件的消息。有過windows編程經(jīng)歷的讀者都會清楚這種機制,Windows下消息處理機制:當在交互中進行一個操作(信號,輸入,等等),windows將產(chǎn)生相應的事件,通過window的事件分發(fā)機制,相應的窗口或者應用得到該事件,從而觸發(fā)相應的事件處理器進行處理。BREW中事件處理機制與其相似,即BREW環(huán)境捕捉到事件后,分發(fā)到相應的應用或者控件,由應用或者控件的事件處理器進行處理。
以下是BREW中事件處理器接口的示例:
?????? boolean MyApp_HandleEvent(IApplet * pIApp,
?????? AEEEvent eCode,
?????? uint16 wParam,
?????? uint32 wParam)
在該示例中,變量pIApp實際上指明了應用的結(jié)構(gòu),也就是AEEApplet的一個指針。許多應用將其結(jié)構(gòu)定義為AEEApplet的超集,而pIApp也能指向該結(jié)構(gòu)。
eCode變量是說明應用接收的事件類型,如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ā)送給應用。短數(shù)據(jù)字段包含主鍵代碼;比如說如果用戶按下按鍵符合“2”,就包含AVK_2這一主鍵代碼。AVK_2的值由AEEVCodes.h頭文件定義。
在Emulator中,與按鍵符號相對應的主鍵代碼由設備配置文件確定,也可經(jīng)由設備配置器進行修改。在手機上,主鍵代碼由設備廠商決定。
4.3.2.2事件處理的提示
執(zhí)行應用時,僅考慮處理應用可能需要處理的事件。許多事件可以被忽略。舉例來說,如果執(zhí)行一個游戲應用時,僅需使用上下左右箭頭鍵,則可忽略接收到的0-9按鍵事件。
但是如果接收到關(guān)鍵事件,則無論應用處于何種狀態(tài)都不能忽略。如EVT_START、 EVT_STOP、EVT_SUSPEND和EVT_RESUME等系統(tǒng)事件就是在任何情況下都會影響應用的例子,所以不能忽略。需要特別注意的是,無論應用給定狀態(tài)如何,必須接收所有的關(guān)鍵事件。某些事件在應用特別指示需要此類通知時才會發(fā)送。應用必須為這些通知事件注冊,可以在MIF編輯器中指定MIF文件的通知事件注冊,或者使用ISHELL_RegisterNotify()進行動態(tài)注冊。
作為一個約定,應用在處理EVT_START分配的任何數(shù)據(jù),在處理EVT_STOP時都應該釋放出去。但是,在AEEClsCreateInstance()中分配的內(nèi)存數(shù)據(jù),一般必須通過FreeAppData()機制來釋放。
4.3.2.3事件分發(fā)與代理
當控件激活時,事件應該傳遞到激活的控件,使控件進行自我更新,又叫做事件代理。例如,如果菜單控件處于激活狀態(tài),應該將事件傳遞到IMENUCTL_HandleEvent();如果文本控件處于激活上,應傳遞到ITEXTCTL_HandleEvent(),然后控件就會采取相應的操作。以菜單控件來說,它就會改變被選項目,重新繪制菜單。
正如事件處理函數(shù)將TRUE或FALSE返回AEE執(zhí)行環(huán)境那樣,控件返回TRUE或FALSE則表示它們處理的事件。每個控件類型只會處理必要的事件。標準菜單控件只處理“上”、“下”和其他部分關(guān)鍵事件,而軟鍵菜單控件則處理“左“、“右”和其他關(guān)鍵事件。如果一個控件從發(fā)放的事件中返回的是TRUE,應用就可以早一點從事件處理函數(shù)中退出來,但還可以執(zhí)行額外的處理。如果一個控件從發(fā)放的事件中返回的是FALSE,應用一般應該繼續(xù)處理該事件。如果該控件接收的是從事件處理器返回的FALSE,BREW就要執(zhí)行默認的處理。
當用戶按下“選擇”鍵進行選擇時,菜單控件使用EVT_COMMAND來通知應用。在這種情況下,一個來自“選擇”鍵下放的EVT_KEY按鍵事件就由菜單控件處理。此外,對于菜單控件任何視圖更新,菜單控件將EVT_COMMAND事件發(fā)回給應用。事實上,所有控件類型都能提供代理機制。
AEE?? Shell
?
My App
?
IMenuCtl
?
?
?
?
?
?
?
?
?
所有的事件
?
按鍵事件
?
?
?
Ture /False
?
Ture /False
?
圖 4-7: BREW中的事件分發(fā)示例
?
?????? 事件的分發(fā)代理機制非常靈活,你可以在消息循環(huán)中按照你的需要自由處理(圖。
用戶按下某一個鍵
?
與該鍵相關(guān)的事件被傳送
給您的事件處理函數(shù)
?
可以將它交給
IMENUCTL_HandleEvent()
?
可以選擇先處理它
?
也可以再次處理它
?
圖 4-8: BREW中的事件代理機制
?????? BREW下的消息處理機制與Windows下的消息處理機制的區(qū)別在于:BREW的體系結(jié)構(gòu)采用了COM方式,即具有面向?qū)ο蟮念悓哟谓Y(jié)構(gòu),從而其具體的事件處理機制也是作為各個接口外露的接口函數(shù)的形式被運用。一個應用本質(zhì)上來說就是一個實例化的IAPPLET類,所以這樣就統(tǒng)一了所有在應用中運用的事件處理機制都是各個接口外露接口函數(shù)的說法。具體而言,這些事件處理器還是有區(qū)別的,主要是IAPPLET_HandleEvent和其他接口的HandleEvent的區(qū)別。
?????? IAPPLET_Handleevent是通過在AEEClsCreateInstance中的AEEApplet_New函數(shù)被注冊實例化的,AEEApplet_New函數(shù)實例化應用同時也通過傳入USERAPP_HandleEvent參數(shù)實例化了IAPPLET_Handleevent。
?????? 除了IAPPLET具有handleevent外,所有的繼承IControl的接口也具有事件處理函數(shù),允許處理事件。這些各種具體的IControl_handleEvent有兩種方式被調(diào)用。一種是在應用的handleevent中由開發(fā)者顯式的調(diào)用,如:
switch (eCode)
{
??? case EVT_APP_START:????????????????????????????
???? return(TRUE);
??? case EVT_APP_STOP:????
……….
??????? Case EVT_KEY:
IMENU_Handleevent….
ItextCtl_Handleevent….
}
另一種是當這些控件包含于對話框中,且處于聚焦狀態(tài)時,這些事件處理函數(shù)的觸發(fā)是隱式的,是由AEE機制自動觸發(fā)的,無需在代碼中顯式的調(diào)用這些handleevent。 IDialog接口沒有外露的handleevent接口函數(shù),但是允許通過IDialog_seteventhandle來注冊一個該對話框的事件處理函數(shù)。需要注意的是該事件處理函數(shù)是何時被觸發(fā)的:一旦當一個對話框處于激活時,AEE層將會把所有的事件直接發(fā)往該對話框,該對話框會自動的調(diào)用處于焦點控件的handleevent來處理該事件,只有當該控件沒有處理該事件時,對話框注冊的事件處理函數(shù)才會被調(diào)用。
當BREW運行后,首先操作系統(tǒng)中的ui 任務會捕捉到各種事件,此時ui 任務通過aee_dispatch將事件分發(fā)至BREW環(huán)境中。BREW環(huán)境再通過aee_sentevent具體分發(fā)事件至目的地,在兩種不同的情況下將走不同的流程。
?????? 如果當前沒有激活的對話框,則緊接著IAPPLET_Handleevent被BREW自動調(diào)用來處理事件,而此時調(diào)用的IAPPLET_Handleevent其實就是用戶注冊的app_handleevent。從而實現(xiàn)了允許用戶的應用捕捉到事件并處理的機制。在用戶的app_handleevent中,用戶可以將事件繼續(xù)下發(fā),比如通過調(diào)用IMENU_handleevent等將事件下發(fā)給各種控件處理。
如果當前有激活的對話框,則基于對話框的事件被BREW自動調(diào)用,從而使得事件被對話框最先截獲,而對話框之后的處理是檢查包含的控件中哪個處于焦點,并將事件下發(fā)給它的handleevent來處理,同時根據(jù)其返回值來判斷其是否已經(jīng)處理了該事件,當其返回False后,對話框?qū)⒃撌录^續(xù)轉(zhuǎn)發(fā)至該對話框注冊的handleevent(如果有的話),如果該handleevent仍然返回false,BREW繼續(xù)將該事件轉(zhuǎn)發(fā)至app_handleevent。這種機制使得當以對話框方式來創(chuàng)建應用時,各種事件被自動的處理,從而簡化了代碼量,但也使得事件流程更加晦澀,用戶的應用程序不能直接的控制它。
?