說明:前面消息的基本知識主要參考《Series60應用程序開發》中的有關內容,後面是前段做MTM開發中用到的代碼。
一、消息存儲基本知識
Symbian OS提供的消息傳送架構基於Client/Server機制,服務器負責管理手機上的各種消息,在進行消息相關操作之前我們需要了解Symbian OS是如何組織和存儲消息的。
手機中的各種消息都是以數據項(Entry)形式供程序操作,數據項有4種類型,SymbianOS爲每種數據項提供了相應的常量標識UID,這些UID保存在msvuids.h文件中:
Ø 文件夾類型,,對應常量UID爲KUidMsvFolderEntry,和PC上的文件系統一樣,每個文件夾可以包含其它數據項也可能是其它數據項的子數據項。
Ø 消息類型,對應常量UID爲KUidMsvMessageEntry,它表示該數據項是一條消息。
Ø 附件類型,對應常量UID爲KUidMsvAttachmentEntry,它表示該數據項是某條信息的附件。
Ø 服務類型,對應常量UID爲KUidMsvServiceEntry,服務數據項包含某個消息服務的配置信息,在一般情況還擁有通過該服務收發的消息數據項。
除了上面提到的四種類型UID還有常用到的UID是KUidMsvRootEntry(msvids.h),它指的是根數據項,根數據項包含了4個標準文件夾數據項,分別是收件箱(KMsvGlobalInBoxIndexEntryId)、發件箱(KMsvGlobalOutBoxIndexEntryId)、草稿箱(KMsvDraftEntryId)和已發送項(KMsvSentEntryId),另外根數據項下面還包含有各種消息服務的服務項,Symbian OS中消息存儲如下圖所示:
Symbian OS中的消息服務器負責保存各種類型的數據項,這裏有兩個基本概念需要了解:消息存儲和消息索引。消息存儲保存了數據項的數據,保存的數據格式取決於消息服務,服務數據項使用消息存儲保存服務配置信息,文件夾數據項不使用消息存儲,Symbian 提供了CMsvStore類來訪問數據項的消息存儲;爲了節省內存和快速檢索消息,消息服務器把數據項的一些概要信息(標題,日期,類型,ID等)寫到消息索引中,當消息服務器啓動時將索引裝載到RAM中直到消息服務器關閉,Symbian提供了TMsvEntry類表示數據項的索引。
操作消息常用的類和數據類型:
CMsvSession
CMsvSession表示客戶端與消息服務器的會話,會用到它獲得下面將要提到的CMsvEntry上下文對象。
TMsvId
它只是一個TInt32的typedef,消息服務器爲每個數據項分配一個惟一的數值做爲標識,除了上面提到的幾個固定的標識,其它的標識都是動態分配的。想要對某個消息進行操作必須先得到它的ID,Symbian中消息相關的大部分函數都會用到TMsvId。
TMsvEntry
上面已經提到過了它表示數據項的索引,只包含消息的一些概要信息,主要會用到Id()成員函數得到數據項的標識ID和公有數據成員iDetails、iDescription和iDate,前面兩個成員可以用來獲取和設置索引的概要信息,iDate成員可以獲取和設置數據項的日期及時間。
CMsvEntry和CMsvServerEntry
CMsvEntry和CMsvServerEntry可以理解爲數據項的上下文(Context),這兩個類非常類似,只不過CMsvEntry用於客戶端,CMsvServerEntry用於實現消息的服務器端,它提供了操作數據項的各種接口,可以根據指定ID定位數據項、獲得消息存儲和消息索引。
CMsvStore
上面已經提到過它表示數據項的存儲,可以通過CMsvEntry(CMsvServerEntry)的 EditStoreL(),ReadStoreL()函數取得可編輯存儲或只讀存儲。
CMsvEntrySelection
CMsvEntrySelection是一個可以存儲TMsvId的數組,在使用CMsvEntry(CMsvServerEntry)的許多操作中都會做爲參數或者返回對象。
二、數據項常用操作
下面的消息操作使用了一個CMsvEntry或 CMsvServerEntry的指針對象,這兩個類提供的功能基本一樣,但有一部分函數名會不一樣,可以查一下SDK。
1. 獲得當前數據項索引和ID
TMsvEntry oldEntry = iServerEntry->Entry();
TMsvId oldContext = oldEntry.Id(); //如果使用CMsvEntry可以直接使用EntryId()
2. 定位到指定數據項
在更換當前數據項之前通常先保存當前數據項索引ID,更換數據項並完成相關操作後再更換回原來的數據項,這可以避免影響其它函數,是一個很好的習慣。
TMsvId oldContext = iServerEntry->Entry().Id();
//使用SetEntry()更換當前數據項到root
iServerEntry->SetEntry(KMsvRootIndexEntryId);
//具體操作後更換回原來數據項
iServerEntry->SetEntry(oldContext);
3. 查找數據項
下面的三個CMsvEntry成員函數都能完成在當前數據項下進行查找的功能:
CMsvEntrySelection* ChildrenWithMtmL(TUid aMtm) const;
根據消息服務(MTM)進行查找,查找消息索引對象(TMsvEntry)的成員iMtm等於aMtm的數據項ID。
CMsvEntrySelection* ChildrenWithServiceL(TMsvId aId) const;
根據消息服務ID進行查找,查找消息索引對象(TMsvEntry)的成員iServiceId等於aId的數據項ID。
CMsvEntrySelection* ChildrenWithTypeL(TUid aEntryType) const;
根據數據項類型進行查找,查找消息索引對角的(TMsvEntry)的成員iType等於aEntryType的數據項ID。
CMsvServerEntry與之相對應的三個函數爲GetChildrenWithMtm(), GetChildrenWithService(), GetChildrenWithType(),注意的一點是CMsvEntry的三個函數都返回一個CMsvEntrySelection對象的指針,使用完之後我們要負責釋放,使用CMsvServerEntry的三個函數需要事先構造一個CMsvEntrySelection對象,用完之後也需要釋放。
找出POP3郵箱個數的代碼
iMsvEntry->SetEntryL( KUidMsgTypePop3 );
CMsvEntrySelection* sel = NULL;
sel = entry->ChildrenWithMtmL( KPkiSmtpTechnologyTypeUid );
TInt cnt = sel->Count(); //獲得集合中數據項的個數
delete sel;
4. 更改消息索引
TMsvEntry entry = iMsvEntry->Entry();
entry.iDetails.Set( _L( “New details” ) );
iMsvEntry->ChangeL( entry ); //把更改後的數據項索引寫回消息索引中去
5. 數據項的讀寫
在進行數據項的讀寫之前需要使用EditStoreL(),ReadStoreL()函數得到相應的存儲CMsvStore通過它提供的接口進行操作。
void CMessageView::ViewMessageL(TMsvId aId)
{
// Construct the CMsvEntry
CMsvEntry* entry = iSession->GetEntryL(aId);
CleanupStack::PushL(entry);
// Get the messaging store
CMsvStore* store = entry->ReadStoreL();
CleanupStack::PushL(store);
// Construct the CRichText and restore the body text
CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
CleanupStack::PushL(paraLayer);
CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
CleanupStack::PushL(charLayer);
CRichText* body = CRichText::NewL(paraLayer, charLayer);
CleanupStack::PushL(body);
store->RestoreBodyTextL(*body);
// Extract body text from CRichText
TInt len = body->DocumentLength(); //get length
HBufC *buf = HBufC::NewL( len );
TPtr ptrBuf = buf->Des();
body->Extract( ptrBuf, 0, len ); //get data
//因爲不同的消息的存儲格式不同,還可能需要對ptrBuf進行相應的解碼才能正常
//顯示
delete buf;
buf = NULL;
CleanupStack::PopAndDestroy(5, entry);
}