[訊息,非同步服務和使用中的物件]
MFC在對無論是初級還是瞭解驅動他們應用程式的訊息迴圈和調度機制的進階程式員隱藏Windows訊息範例方面做得很好。在Symbian 作業系統中,驅動應用程式的是一套完全不同又十分強大的機制,被稱為使用中的物件。它與Symbian作業系統的用戶端-伺服器端結構緊密結合,提供了各種系統服務,同時也可以為程式員來給他們可能需要為應用程式建立的任何非同步服務建立乾淨、標準的介面。
簡而言之,CActiveScheduler執行了Windows訊息迴圈,在一個給定線程內提供了共用的多任務,CActive(一個使用中的物件)充當了訊息處理者。在Symbian 的使用者介面架構中,這要比MFC 把訊息隱藏得更好:接收到的訊息總是由架構調度給預先定義的可以被應用程式重載的方法——比如OfferKeyEventL(處理鍵盤輸入)。
定時器是使用了使用中的物件架構的簡單系統服務的一個執行個體。不同於Windows 中調用StartTimer 來觸發WM_TIMER 訊息的做法,Symbian 作業系統中是由一個CTimer 對象與系統時鐘服務進行互動,RTimer 與其RunL 函數根據由API 規定的時間間隔被調用。程式員從CTimer 繼承到一個對象,並重載RunL 方法。
其它的非同步系統服務,如Nokia 7650 上的照相機功能也是通過類似方法提供的。CCameraManager 定義了一個使用中的物件提出拍照操作的請求並隨即獲得通知。實際的非同步服務是由RCameraServ 提供的,但是典型的程式員根本用不著處理任何用戶端-伺服器端或者顯式的處理序間通訊問題。
使用使用中的物件時,頭腦中時刻牢記使用中的物件何時按預定計劃執行這個很簡單的準則非常重要。這就是說,到底什麼時候CActiveScheduler 會調用一個CActive 對象的RunL 方法呢?
·CActive 對象必需是“活動”的。這是通過調用Cactive::SetActive 實現的,通常在使用中的物件自己對應用程式某個請求做出的響應中完成。
·CActive 對象的狀態,由成員變數iStatus 所示,一定不能為KRequestPending。這個值表示該對象正在等待服務完成。通常在提出一個服務要求時變數iStatus 才會被服務提供者設為KRequestPending。iStatus 隨後在服務結束時被服務者提供者更新。
·CActiveScheduler 需要接收到一個訊號——該訊號由非同步服務在結束時發出。
當非同步進程對應用程式發出結束訊號,然而沒有準備好的CActive 對象時,就會產生一個“迷失”訊號。這在以下幾種情況下可能發生:
·你忘記了使用CActive::SetActive 使使用中的物件處於“活動”狀態。
·服務提供者在發出操作完成訊號時忘記將iStatus 置為非KRequestPending 的值。這隻會在你寫了錯誤的服務提供者時出現——典型的應用程式會使用系統定義的服務。
·服務提供者給同一個操作發出了不只一個終止訊號。
第三種情況在服務提供者設計不夠仔細的情況下可能發生。例如,有一個服務已經結束並且對用戶端通知了這一事實,但是用戶端恰恰在收到這個通知之前發出了取消服務的請求。服務提供者必需忽略這一當前不合理的請求。要是服務提供者沒有忽略這一請求,而是對它做出響應並給出一個附加訊號說已經結束了,會是怎麼樣呢?在這種情況中,附加的訊號最終就會成為“迷失”訊號,並會引起程式出錯。這對於錯誤修正來說很困難,因為“迷失”訊號是被CActiveScheduler 檢測到的,沒有顯示是什麼CActive 對象的責任。
CActive 對象必需確保在各種情況下與服務相關聯的終止訊號都恰當。在解除程式中應該典型的具有一個CActive::Cancel 調用。如果Cancel沒有被調用,而對象在有請求仍被掛起時就被刪除,錯誤就會發生。而且,每個CActive 對象必需以確保任何由該對象請求的服務都被取消的方式執行CActive::DoCancel,否則CActive::Cancel 就會一直等待服務提供者的終止訊號。這兩種錯誤都很難被檢測到,因為它們只在存在明顯的請求時才會被發現。