Room,Realm,,ObjectBox 你选择哪个?

原文:Realm, ObjectBox or Room. Which one is for you? 

面对数据存储的时候,Android开发者有太多的库可以选择了。不管是对象映射还是数据集合,都有相应的工具可用。一些是开箱即用,比如 shared preferences 和 纯 SQL,其他的则需要外部依赖。放心,我这里不会讨论关于写复杂的数据查询语句的事情。相反,我将比较几个一流的库:新发布的Room Persistence Library,有些年生的Realm,以及不太为人所知的ObjectBox,一个最近出了beta版本的库。

最终的选择我留给你自己,但是谁是第一在文章的最后应该大致清晰了。在这之前,我们先一一介绍它们。

Realm 

自从它诞生以来(大概2011,最初叫做“TightDB”),Realm就成为了很多开发者的选择。为什么?简单(几乎是使用标准的Java对象),速度(大部分用C++编写)以及无需写SQL。创建一个Realm数据库很简单,其使用也很简单。这个库只需很少的设置,官网的文档解释的很详细:

首先需要的是一个代表存储对象的model:

open class Box (
@PrimaryKey var size: Long = 0, 
var name: String = "", 
@Ignore var tempReference: Int = 0) : RealmObject() {}

唯一值得一提的是如果你使用Kotlin,所有的成员都必须要有默认值。注解和继承RealmObject这都是一看就懂的,所以我们继续。

使用Realm:

Realm.init(context)
val realm = Realm.getDefaultInstance()
val box = realm.where(Box::class.java).findFirst()
realm.executeTransaction {
//modifying an exsiting object
 box.size = 20
 box.name = "John"
//creating a new object
 val secondBox = realm.createObject(Box::class.java)
 secondBox.size = 30
}

Full example

Room Persistence Library 

Room是Google最新的也是最亮眼的库,在官方的架构指南中也占据着核心的位置,Room提供了一个SQLite之上的抽象层,使得在充分利用SQLite功能的前提下顺畅的访问数据库。它很好的封装了 SQL,把容易理解的 Java 方法暴露给开发者。还记得我说过没有sql查询?好吧,现在我准备写点查询语句,不过别担心,Room提供了一些安全机制,出现严重的错误会提出警告。

鉴于现在Room已经比较受欢迎,对它的介绍我尽量简短一些。

Room有三个主要的组建,都是用注解来表示:

Database: 你可以用它来创建一个数据库。这个注解定义了Entity的列表,以及数据库中的data access objects(DAO)。同时它也是底层连接数据库的入口。

这个注解类必须为一个继承RoomDatabase的抽象类。你可以使用Room.databaseBuilder() 或者 Room.inMemoryDatabaseBuilder() 来实例化它。

Entity: 这个组建代表数据库中的表。对每一个entity,数据库都创建一张表来持有。你必须在Database类的entity数组中引用entity类。

DAO:这个组建代表Data Access Object类或者接口。DAO负责定义操作数据库的方法。@Database注解的类中必须包括0参数的返回 @Dao类的抽象方法。

下面是实现了所提到的组建代码(无耻的拷贝自 这篇 文章):

@Entity(tableName = “task”)
data class Task(@ColumnInfo(name = “completed_flag”) var completed: Boolean = false,
 @ColumnInfo(name = “task_desciption”) var description: String) {
 @ColumnInfo(name = “id”)
 @PrimaryKey(autoGenerate = true) var id: Long = 0
}
@Dao interface TaskDao {
 @Query(“select * from task”)
 fun getAllTasks(): List<Task>
@Query(“select * from task where id = :p0”)
 fun findTaskById(id: Long): Task
@Insert(onConflict = REPLACE)
 fun insertTask(task: Task)
@Delete
 fun deleteTask(task: Task)
}
@Database(entities = arrayOf(Task::class), version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun taskDao(): TaskDao
}

创建一个数据库以及调用它的方法就如下面这般简单:

var database = Room.databaseBuilder(context, AppDatabase::class.java,”db”).allowMainThreadQueries().build()
database.taskDao().insertTask( Task(description = “simple!”) )

ObjectBox 

作为一个最新的成员,ObjectBox为我们带来了很多东西。但是在门槛已经被拉高的情况下,这个新的NoSQL技术能与前面的战场老兵相比吗?如果它想要与 Realm 和 Room 比肩,必须使出一记重锤才行。也的确不只使出了,还不止一记,而是一套。这里是它最典型的亮点:

  • 速度:跟Realm一样,ObjectBox提供了出色的性能,有时还超越了。

  • QueryBuilder:ObjectBox只需要你查询对象,并在编译时检查。

  • Object Relations: Object references / relationships are a built-in type; they are native references

  • 不需要手动迁移 : 升级是完全自动的,不需要关心属性的变化以及命名的变化

  • 更多

那么实际使用是什么样的呢?

model是必须的:

@Entity
data class Note (
 @Id var id: Long = 0,
 val text: String
)

ObjectBox通过叫做Boxes的东西来存储对象的数据。要使用ObjectBox来管理数据库,你只需两步:

一个 “Box Store” 对象,在Application 中初始化:

MyObjectBox.builder().androidContext(App.this).build()

以及每一个model对应的“Boxes”。这些box负责与数据库的交互。

var notesBox = boxStore.boxFor(Note::class.java)

一个重要的细节是这些Box类型是自动生成的,不需要额外的担心!

好了之后,你就可以开始使用了,下面是一些可以使用的方法:

notesBox.put(note)
notesBox.remove(note)
notesBox.count()

要了解Box class的所有方法,请看它的 JavaDoc。这里要注意的是,名为一个 DaoCompat 的兼容层可以让ObjectBox使用类似greenDAO的API。

比较

到目前为止,所有的库几乎都做的是一样的事情,有些要用SQL,有些不。但是能让我们感兴趣的是它们的不同点。下图中,我们使用开源的排名app 测试了三种方式的性能。

这个结果比较有趣,是吧?测试结果清楚的表明,大多数时候,ObjectBox都碾压所有对比。而且随着测试数据的增多,差距就更大了!

查询也是似乎也是ObjectBox的强项之一。测试主要针对索引和字符串,结果显而易见。

那么apk大小呢?这些库分别会给项目带来多少负担呢?我们可以使用最新发布的 apk analyzer来看看它们各自到底有多大。

ObjectBox 和 Realm 分别占用了 1–1.5MB 和 3–4MB(大小取决于手机的架构),而Room,作为一个SQL的封装,只占用了大约50kb。但是作为一个忠实的Android开发者,我们还必须遵守烦人的方法数限制。在这方面,Room似乎再一次领先,只有300个方法。ObjectBox和Realm分别是1300和2000个方法。

功能方面,每个库都提供了自己的额外功能。Room除了提供SQLite能做的所有事情之外,还添加了更多。比如完全可测试的迁移机制。相反ObjectBox并不需要,因为它自己处理了绝大部分迁移(虽然某些改变需要额外的工作)。Realm提供的功能最多,包括自定义配置,加密等等(体积比较大的原因之一)。

总结

可以看到不管你选择哪个都有它的优缺点。如果你追求速度和效率,明显选择ObjectBox。但是如果你受限于app大小,方法数已经接近于64k 的限制,也愿意处理SQL,Room可能是适合你的方案。Realm,虽然不是最快的,也不是最小的,但是有着7年的调试和改进支撑,它可以提供最稳定的,bug最少的,最健全的方案。

答案留给你自己 ,但是记住,app的好坏取决于你自己的选择(以及你的代码质量,不过这是另一个话题)。