【Android】数据库工具 Cupboard

原创
2015/12/09 13:08
阅读数 108

#Cupboard Tips

Cupboard 官方托管

翻译与示例托管

##Cupboard for Android

Cupboard 是针对 Android 的一个简单的持久化存储方案,简单而且容易与现有代码集成。

更准确的说, Cupboard 是一个存取对象的方式。并不是一个真正的ORM,因为为了保持简单,它并不会去维护对象之间的关系。

###设计理念 设计 Cupboard 是因为现有的持久化框架并不能满足实际的需求:

  1. 想要一个非侵入的:不必要继承某个特殊的Activity,你的 model 也不必要无实现某个特殊的接口,如果不愿意,都不必要实现 DAO 模式
  2. 需要一个通用的选择:在整个应用中都可以使用所定义的 model 对象,而并不局限于数据库
  3. 需要完美适应 Android 自有的类,比如 Cursor 以及 ContentValues,这样,可以在任何时候回退到 Android 框架里面。

###使用方式/Using Cupboard

引入 Cupboard 依赖,然后静态导入 cupboard():

build.gradle:

compile 'nl.qbusict:cupboard:(insert latest version)'
最新是 2.1.4 所以可以这么写: compile 'nl.qbusict:cupboard:2.1.4'

java 类:

import static nl.qbusict.cupboard.CupboardFactory.cupboard;

在代码中可以这么调用:

public long storeBook(SQLiteDatabase database, Book book) {
    return cupboard().withDatabase(database).put(book);
}

上面的代码将一个 Book entity 存入数据库中,然后返回记录的 id, 就这么简单。

###Entities

Cupboard 中的 entity 就是一个POJO,Cupboard使用反射来操作字段,没有使用注解,因为 Android 中的注解反射实在是太低效了。

entity 在使用之前,需要先使用 Cupboard.register() 进行注册。一个示例:

public class Book {
    public Long _id;
    public String title;
    public Author author;
    public Date publishDate;
}

entity 的字段名对应 SQLite 数据库中的 列名,表名根据 entity 名得来,本例中,表名就是 book。 每个 entity 都应该有一个 Long 类型的 _id 字段,采用 Long 类型是因为这样 _id 就可以取 null了。 而且,Android 原生的 Cursor 本身就期望一个 _id。 entity 的一个字段可以是任何基本类型,相应的包装类,java.util.Date,或者另一个 entity 。

###Operations

你可以:

  1. 使用 put 来创建或者更新一个 entity
  2. 使用 get 来获取一个 entity
  3. 使用 delete 来删除一个 entity
  4. 使用 query 来查询 entity

当使用 withDatabase() 【见后文】的时候,也可以像使用 SQL 一样来执行 update 操作。

###Compartments

在许多通常的应用中,你需要从不同的组件访问 model,比如 ContentProvider 可能就持有 SQLiteDatabase 的连接,然后你从 Activity 或者 Service 来访问。

如果你只能在 ContentProvider 使用持久化库,而在其他组件里面只能使用原始的 ContentValues, 这不就是一个笑话吗。

Cupboard 以及预料到这一点:

SQliteDataBase db = getDatabase();

// 将一个 entity 保存到数据库中
cupboard().withDatabase(db).put(book);
Cursor cursor = getCursor();

// 从 cursor 获取第一个条记录
Book book = cupboard().withCursor(cursor).get(Book.class);

// 遍历所有的记录
Iterable<Book> itr = cupboard().withCursor(cursor).iterate();
for (Book book : itr) {
  // do something with book
}

// 使用 content provider 来保存一条记录
Uri bookUri = ...
cupboard().withContext(this).put(bookUri, book);

//将 Book  entity 传递给另一个需要 ContentValues 对象参数的方法
ContentValues values = cupboard().withEntity(Book.class).toContentValues(book);

// 我们可能正在构建一组 ContentProviderOperation 
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(10);
Book newBook = new Book();
...
cupboard().withOperations(ops).put(bookUri, book).put(bookUri, newBook);

##官方文档翻译

  1. Working_with_databases
  2. Working_with_ContentProviders
  3. Working_with_Cursors
  4. Working_with_existing_data_structures_and_annotation_support
  5. Custom_Converters
  6. ProGuard_configuration

##Demo

参见工程 app

##Q&A

###_id的生成机制 注意每个 model 里面定义的 _id,Cupboard 要求使用 Long 类型,这样就可以根据 _id 是否为 null 来判断是否需要自动分配 _id。 当然,你也可以定义为 long 或者 int 等等任意其他类型的数值,但是,由于数值的默认值都是 0,因此,Cupboard 无法判断这个值到底是默认值还是用户赋值。 从而需要用户自己来为维护 _id 的分配。比如,定义如下:

public class SimpleBook {
    public long _id;
    public String title;
}

如果你使用下面的调用:

SimpleBook simpleBook = new SimpleBook();
simpleBook.title = "title_single_" + System.currentTimeMillis();
cupboard().withDatabase(cupboardSQLiteOpenHelper.getWritableDatabase()).put(simpleBook);

那么,不论你调用多少次,数据库里面只会得到一条数据,而且 _id = 0;所以除非你手动赋值 _id:

SimpleBook simpleBook = new SimpleBook();
simpleBook._id = System.currentTimeMillis();
simpleBook.title = "title_single_" + System.currentTimeMillis();
cupboard().withDatabase(cupboardSQLiteOpenHelper.getWritableDatabase()).put(simpleBook);

所以,如果 _id 没有特别的需求,还是按照 Cupboard 默认要求。

###Q群:315658668

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部