代码改变世界

[转] Android与db4o的完美结合:Password Manager

2011-08-16 12:58  唐郎  阅读(1255)  评论(3)    收藏  举报

项目简介

  这里提供的Password Manager项目是Steven Osborn编写的PasswordSafe(在Apache License下发行)的改写版,目前已经实现了在Android平台下的基本密码管理功能。项目源代码中使用db4o代替了SQLite,这样不但使持久化处理更为直观,而且使开发过程更快速、整个应用更加高效。

  在这个项目中,你可以获得以下资源:

  db4oSQLite之间在基本持久化操作上的比较

  完整的Android示例应用代码

  应用运行时的视频演示

基本功能

  本应用基本功能是安全地保存网站登录信息,例如URL、用户名、密码,它使用128AES加密算法。使用者必需提供正确的密码才能访问应用,而密码被用于加密/解密应用数据。

  这里提供了采用db4o技术的Password ManagerAndroid模拟器下运行的在线视频:

  http://www.youtube.com/watch?v=UFSD44AcBwM

  如果你下载了源代码(请见本页末尾的详细说明),那么你会看到原来PasswordSafe中的DBHepler类(实现SQLite下的持久化)已经被替换为Db4oHelper类(实现db4o的持久化)。现在,就让我为你展示db4oSQLite在持久化处理上的不同之处吧!

SQL初始化开销

  这是你需要在SQLite下初始化密码管理器SQL代码(表名、表创建命令等):

   

  而下面是等价的db4o代码:

   

  正如你所看到的,在db4o中无需预定义schema(你可以将db4o对象模式当作schema使用,并且在这种对象模型下进行重构是非常优雅的,甚至在一些简单的情况下是自动化的)。

数据库打开和创建机制

  在SQLite中,你需要调用两种不同的方法,一种是创建数据库,另一种是打开数据库:

  而在db4o中,你只需要调用openFile(),它将根据数据库是否存在来创建或者打开数据库:

  也许这里的差别看起来无关紧要,但更简短的代码才是更清晰的代码!

更新和插入数据

  使用关系数据库SQLite时,你需要根据具体情况传送插入或更新命令(完全正确地构造反射数据表字段的SQL字符串确并非易事):

  这里是等价的db4o代码:

  你是否发现了不同?db4o实际上是一种单行代码(one-line-of-code)的存储数据库。db4o自动检查对象是新的还是已存在的,并根据对象状态进行更新或者插入(我们只需要调用set操作)。值得注意的是,在上面的代码中我们手工提供了对象的新id,而db4o是可以将其配置为自增字段的。

 

配置自增Id?

这里我依然保持疑问, 据我说知,db4o中的Id System有两种, 一个是物理Id(即指向对象镜像存储位置的指针),一个是UUID(需要在创建数据库时指定配置项), 都与自增无关。

ID:
long id=db.ext().getID(object);
db2.ext().bind(o2,id);
Object o=db.ext().getByID(id);

通过getByID得到的对象并未激活,如果要使用还要手动去激活
Db.active(o3,1)

如果对象含有复杂属性,那么必有手动去获得每个属性的ID,每个对象的ID是唯一的,即使关闭数据库后重新打开仍然不变,除非使用碎片整理工具对数据库文件进行碎片整理

UUID:
config.objectClass(SomeClass.class).generalUUIDs(true);
ObjectInfo info=db.ext.getObjectInfo(obj);
Db4oUUID uuid=info.getUUID();
SomeObject so=(SomeObject)db.ext().getByUUID(uuid);


Index:
config.objectClass(SomeClass.class).objectField(“fieldname”).indexed(true);

 

查询所有记录

  在SQLite中,我们不得不进行人工的对象关系映射:

    而在db4o中,我们完全可以忘掉关系映射:

  请注意:在上面简短的查询中,我们通过db4oSODA查询了全部PassEntry对象,并将结果按照"id"字段进行排序(在上面的SQLite示例中没有排序)。

  它不能再简单了!

通过字段查询单一记录

  通过Id查询记录的SQLite版本:

  下面是db4o版本,它使用了db4o三种查询系统之一------Exmaple(也称为QBE)代替前面的SODA进行查询:

  可以看出这是多么短小、清晰的代码啊!

结论

  我希望你已经通过以上短小的文档了解到了db4o的优点。你希望在应用中将持久化提升到一个新的高度吗?请现在就下载db4oJava版本或者.NET版本吧!它是免费的!

  相关资源

  db4o指南

  安装向导

  开发者资源

TODO

  使用XTEA替换自定义加密算法(XTEA能够提供数据库级别加密和IO加密,而不是字段级加密)

  提供检索功能(为了按名称进行过滤)

  StevePasswordSafe项目发布在Google Code上,那里有更多的TODO

  http://code.google.com/p/android-passwordsafe/issues/

  Bugs

  在密码记录编辑器中尝试编辑website输入框中的URL时会发生错误。

 

以下内容引用自DB4O手册:

15. IDs


The db4o team recommends, not to use object IDs where this is not necessary. db4o keeps track of object identities in a transparent way, by identifying "known" objects on updates. The reference system also makes sure that every persistent object is instantiated only once, when a graph of objects is retrieved from the database, no matter which access path is chosen. If an object is accessed by multiple queries or by multiple navigation access paths, db4o will always return the one single object, helping you to put your object graph together exactly the same way as it was when it was stored, without having to use IDs.

The use of IDs does make sense when object and database are disconnected, for instance in stateless applications.

db4o provides two types of ID systems.

15.1. Internal IDs

The internal db4o ID is a physical pointer into the database with only one indirection in the file to the actual object so it is the fastest external access to an object db4o provides. The internal ID of an object is available with

objectContainer.ext().getID(object);


To get an object for an internal ID use

objectContainer.ext().getByID(id);


Note that #getByID() does not activate objects. If you want to work with objects that you get with #getByID(), your code would have to make sure the object is activated by calling

objectContainer.activate(object, depth);


db4o assigns internal IDs to any stored first class object. These internal IDs are guaranteed to be unique within one ObjectContainer/ObjectServer and they will stay the same for every object when an ObjectContainer/ObjectServer is closed and reopened. Internal IDs will change when an object is moved from one ObjectContainer to another, as it happens during Defragment .

15.2. Unique Universal IDs (UUIDs)

For long term external references and to identify an object even after it has been copied or moved to another ObjectContainer, db4o supplies UUIDs. These UUIDs are not generated by default, since they occupy some space and consume some performance for maintaining their index. UUIDs can be turned on globally or for individual classes:

Db4o.configure().generateUUIDs(Integer.MAX_VALUE);
Db4o.configure().objectClass(typeof(Foo)).generateUUIDs(true);


The respective methods for working with UUIDs are:

ExtObjectContainer#getObjectInfo(Object)
ObjectInfo#getUUID();
ExtObjectContainer#getByUUID(Db4oUUID);