随笔 - 6  文章 - 8 评论 - 13 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(2)

随笔分类(4)

文章档案(8)

Symbian Resources

VC Resources

搜索

  •  

最新评论

阅读排行榜

评论排行榜

首先在文件和目录篇中我们介绍了系统RAM主要用于活动程序和系统内核,另外可作为用户使用的磁盘空间c:盘访问。其实,通信录中的数据就是存在RAM中的,至于操作这些数据的众多功能则是由通信录模型(Contacts Model)提供的。
首先在文件和目录篇中我们介绍了系统RAM主要用于活动程序和系统内核,另外可作为用户使用的磁盘空间c:盘访问。其实,通信录中的数据就是存在RAM中的,至于操作这些数据的众多功能则是由通信录模型(Contacts Model)提供的。

接下来我们就来简单的讲述一下通信录模型的结构,它是基于一个通信录数据库,数据库中含有一些通信录项。每个通信录都有一些域,诸如姓名、地址,以及电话号码等。某台移动电话可能有好几个通信录数据库,但总会有一个默认的数据库。在我工作的环境中(S60 Sdk 2.1) ..\Symbian\7.0s\Series60_v21_C\Epoc32\wins\c\system\data\Contacts.cdb
就是模拟器默认的数据库。
我们知道在
手机应用开发中经常会遇到有关OBEX协议的问题,其实在通信录开发中也遵循这个协议,通信录中的数据是存在一个名叫vCard的载体里。vCard是一类电子名片,得到许多电子设备(如PDA和移动电话等)的支持。vCard的目的是:在这些设备之间用某些协议实现方便的通信录数据传递。可以将vCard编码成MIME规范(RFC 1521)所定义的明码文本。这种编码确保了各种vCard与限制为7位字符集(如在SMS消息中使用的编码)的传递编码的完全兼容。
一张vCard被格式化如下:
BEGIN:VCARD
VERSION:2.1
N:Wilkinson;Steve
FN:Steve Wilkinson
ORG:EMCC Software Ltd.
TEL;WORK;VOICE:01617779700
ADR;WORK;ENCODING=QUOTED-PRINTABLE:;;108 Manchester Rd.=0D=0ACarrington;Manchester;UK;M31 4BD;United Kingdom LABEL;WORK;ENCODING=QUOTED-PRINTABLE:108 Manchester Rd.=0D=0ACarrington=0D=0AManchester, UK M31 4BD=0D=0AUnited K= ingdom
EMAIL;PREF;INTERNET:steve.wilkinson@emccsoft.com
REV:20030909T164330Z
END:VCARD
通信录模型中的许多功能都与vCard的处理有关,以保证Symbian应用开发伙伴们能方便地编制符合电子名片及通讯录交换方面的工业标准的代码。

具体实践之前先来简单介绍几个类:
CContactDatabase类用于创建一个新的数据库或打开一个现有的数据库。还提供了访问各通信录项的功能。既可以读取也可以打开通信录项。如果希望编辑或删除该项,就必须打开它,尽管一个应用在某个时间点只能打开一个特定的通信录项。当完成对通信录项的修改后,即把它们提交给数据库保存。当然这个类还提供了很多其他的功能,例如排序、查找等等。这个类是通信录操作中很重要的一个类。

通信录模型提供了MContactDbObserver类,某个应用可以继承自这个类,用于接收由某个特定的通信录数据库所产生的修订提示。使用该观察者(observer)的那些应用会接收事件提示,这些事件可以是向数据库中添加一个新通信录、修改或删除一个现存的通信录,以及一定范围内的其他有用提示。

所有通信录项都继承自抽象类CContactItem,对其访问是通过前面讲过的CContactDatabase类管理的。可以用CContactItem::Id()函数(该函数返回一个TContactItemId)来获取每个通信录项的唯一ID。CContactItem类也含有对通信录项内部的域进行操作的功能。可以添加及插入新域,也可以删除项目中的现有域。

某个通信录项内部的一些域由CContactItemField类所代表。为方便起见,位于某个特定项内部的所有域都被储存在一个结构内部,该结构被称为一个域集(CContactItemFieldSet)。每个通信录域储存了实际的域数据,以及针对该数据的一个特定储存类型。这可以是一个文本串、一个数据/时间值、一个商店,或者一个代理,它由TStorageType类代表。一个代理域基本上是对另一个通信录的链接,如,Series 60 Platform就是这样实现的:将其他通信录项的ID联系到该通信录域。请注意:这里并不支持数字表示的通信录域。所有数字信息,如电话号码和传真号码,都被作为文本保存。
接下来我们的实践会用到上面的部分类,所以上述的类大家需要认真熟悉一下,更多的细节也可以查找相关sdk的help文件。

打开、关闭数据库
CContactDatabase::OpenL()函数有两个重载函数。如果该函数没有给出一个参数,就打开默认的数据库。另一种情况是,应用设计师也可以传递一个有关数据库的路径和文件名,规定打开另一个数据库。
-------------------------------------------
// Open the default contacts database.
CContactDatabase* contactsDb = CContactDatabase::OpenL(); //打开默认数据库
CleanupStack::PushL(contactsDb);
// Count how many contacts are in the default database and then
// delete the CContactDatabase object.
// Note that all resources owned by the contacts database are freed
// upon deletion.
TInt numberOfContacts = contactsDb->CountL(); //所有数据项数目
CleanupStack::PopAndDestroy(contactsDb);//销毁
-------------------------------------------
要注意的是:某个通信录数据库并不具有Close()函数或类似的函数。

新建数据库
CContactDatabase::CreateL()函数与CContactDatabase::ReplaceL()函数之间的唯一差别就是:如果该数据库已经存在,前者会以KErrAlreadyExists退出。如前所述,如果没有定义参数,这些函数将创建一个默认的数据库。CContactDatabase::FindContactFile()函数给出了一个描述符,如果不存在默认数据库的话,该描述符就会返回该默认数据库的位置。
-------------------------------------------
// If one is found, replace it with a new empty default database.
// If no default database is found, create a new one.
TFileName contactDbFilePath;
CContactDatabase* newDefaultContactDb; if(CContactDatabase::FindContactFile(contactDbFilePath)) //是否存在默认数据库
{ newDefaultContactDb = CContactDatabase::ReplaceL();
}
else
{ newDefaultContactDb = CContactDatabase::CreateL();
}

CleanupStack::PushL(newDefaultContactDb);
// 添加自己功能代码
CleanupStack::PopAndDestroy(newDefaultContactDb);
-------------------------------------------

遍历通信录项
可以用TContactIter类来遍历一个通信录数据库。这个类提供了一整套的函数,用于遍历所有的通信录项。所有的函数都用通信录项ID (TContactItemId) 进行操作,该ID 用于访问某个特定的通信录项。
-------------------------------------------
// Open the default contacts database:
CContactDatabase* contactsDb = CContactDatabase::OpenL(); CleanupStack::PushL(contactsDb);

TContactIter iter(*contactsDb); //类似游标
TContactItemId cardId;

while( ( cardId = iter.NextL() ) != KNullContactId ) //循环遍历
{
CContactItem* card = contactsDb->ReadContactL(cardId); //读取相应项
CleanupStack::PushL(card);

//添加自己功能代码

contactsDb->CloseContactL(card->Id());
CleanupStack::PopAndDestroy(); // card
}
CleanupStack::PopAndDestroy(); // contactsDb
-------------------------------------------

导出所有通信项到文件
主要使用类CContactDatabase中ExportSelectedContactsL函数。s60 2.1help中定义如下:
-------------------------------------------
void ExportSelectedContactsL(const TUid& aFormat,const CContactIdArray& aSelectedContactIds,RWriteStream& aWriteStream,TInt aOption,TBool aExportPrivateFields=ETrue);
void ExportSelectedContactsL(const TUid& aFormat,const CContactIdArray& aSelectedContactIds,RWriteStream& aWriteStream,TInt aOption,const CVersitParser::TVersitCharSet aCharSet, TBool aExportPrivateFields=ETrue);

Supported from 6.0

Description:
Exports an array of contact items to a write stream — overloaded function. The items are converted into vCards before being written to the stream.

Parameters:
const TUid& aFormat:Indicates the format for imported and exported contacts. Must have a value of KVersitEntityUidVCard.

const CContactIdArray& aSelectedContactIds:Array of contact IDs to export.

RWriteStream& aWriteStream:The stream to write to.

TInt aOption:Indicates the options for import and export. See the TOptions enum.

const CVersitParser::TVersitCharSet aCharSet:The character format. If not specified, defaults to CVersitParser::EUTF8CharSet.

TBool aExportPrivateFields=ETrue:ETrue exports fields marked as private. EFalse does not export fields marked as private. See CContactItemField::SetPrivate().

Leave codes:
KErrNotSupported aFormat.iUid is not KVersitEntityUidVCard.
KErrNotFound One or more of the contact items does not exist in the database.
-------------------------------------------
例程如下:
-------------------------------------------
RFs fileSession;
User::LeaveIfError(fileSession.Connect());//连接文件服务器
CleanupClosePushL(fileSession);
CContactDatabase* contactDb = CContactDatabase::OpenL();//打开默认数据库
CleanupStack::PushL(contactDb);
CContactIdArray* exportContact = CContactIdArray::NewL();//记录数据项数组
CleanupStack::PushL(exportContact);

RFile file;
file.Replace(fileSession,aFileName,EFileWrite);//新建文件,aFileName是文件名字
CleanupClosePushL(file);
RFileWriteStream outputStream(file);//声明文件流
CleanupClosePushL(outputStream);

exportContact = iContacts;//iContacts是已初始化了相应导出属性的数组,需用类CCntFilter
//如:
//CCntFilter* filter = CCntFilter::NewLC();
//filter->SetContactFilterTypeALL(EFalse);
//filter->SetContactFilterTypeCard(ETrue);//按vCard格式导出
//contactDb->FilterDatabaseL(*filter); //按照该filter属性取出满足条件的相应项
TUid id;
id.iUid = KVersitEntityUidVCard;
contactDb->ExportSelectedContactsL(id,*exportContact, //导出到文件
aWriteStream,
CContactDatabase::EExcludeUid);

CleanupStack::PopAndDestroy(5);
-------------------------------------------

删除一个指定通信录项
这里可以使用类CPbkContactEngine,这个类可以很方便的完成各种操作,它相当于操作手机通信录的一个快速引擎
使用时:
CPbkContactEngine* iPbkContactEngine = CPbkContactEngine::NewL();
这样它就会建立一个默认通信录的引擎对象。
然后:
-------------------------------------------
IMPORT_C void CPbkContactEngine::DeleteContactL ( TContactItemId aContactId,
TBool aImmediateNotify = EFalse
)
IMPORT_C void CPbkContactEngine::DeleteContactsL ( const CContactIdArray & aContactIds,
TBool aImmediateNotify = EFalse
)
-------------------------------------------
上述两个函数都可以完成删除操作,只是一个是每次删除一个特定Id的通信录项,另一个是删除一个满足条件的通信录项数组。
可以简单的调用实现:
iPbkContactEngine->DeleteContactL(id);
删除后最好调用iPbkContactEngine->CompressL();将数据库进行下压缩,因为压缩比较消耗时间,所以不要每次删除都进行。

当然有了上面的类CPbkContactEngine,我们还可以实现新建和修改通信录项的功能,其实我们在文章开始时讲述的几个类也可以完成同样的功能,但相对于这个类,操作相对复杂一点,究竟选用什么类,只是你自己的爱好。
下面举例说明实现新建和修改操作:
新建
-------------------------------------------
//省略部分声明代码(与上面重复)
...
CPbkContactItem* contact = engine->CreateEmptyContactL();//新建一空通信录项
CleanupStack::PushL(contact);
_LIT(KFName,"King");
_LIT(KLName,"Chai");
_LIT(KNumber,"13777777777");
//修改first name
TPbkContactItemField* field = contact->FindField(EPbkFieldIdFirstName);
field->TextStorage()->SetTextL(KFName);
//修改last name
field = contact->FindField(EPbkFieldIdLastName);
field->TextStorage()->SetTextL(KLName);
//修改手机号码
field = contact->FindField(EPbkFieldIdPhoneNumberMobile);
field->TextStorage()->SetTextL(KNumber);
...//可以添加其他值
//修改后结果添加到数据库中,并返回这个通信录项的id,可以以后使用
TContactItemId Id = engine->AddNewContactL(*contact);

CleanupStack::PopAndDestroy(contact);
-------------------------------------------
实现修改和新建的代码类似,不同是你需要找到你要修改的field,然后修改,最后导入数据库
修改
-------------------------------------------
CPbkContactItem* contact = engine->OpenContactLCX(aContactId);
CleanupStack::PushL(contact);
//找到需要修改的field
TPbkContactItemField* field = contact->FindField(EPbkFieldIdPhoneNumberMobile);
CleanupStack::PushL(field);

_LIT(number,"13500000000");
TBuf<11> phonenumber(number);
//设置并确认修改
field->TextStorage()->SetTextL(phonenumber);
engine->CommitContactL(*contact);

CleanupStack::PopAndDestroy(2);
posted on 2007-05-04 23:52 Boon 阅读(134) 评论(0)  编辑 收藏 引用