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