realm是一个跨平台移动数据库引擎,支持iOS、OS X(Objective-C和Swift)以及Android。相比SQLite,Realm更快并且具有很多现代数据库的特性,比如支持JSON,流式api,数据变更通知,以及加密支持,这些都为安卓开发者带来了方便;
下面我们来看看如何在Kotlin的项目中集成Realm:
安装:
Realm 作为一个 Gradle 插件来安装需要如下两个步骤:
- 在项目的 build.gradle 文件中添加如下 class path 依赖
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:2.1.1"
}
}
- 在 app 的 build.gradle 文件中应用 realm-android 插件
apply plugin: 'realm-android'
Realm数据模型定义需要继承RealmObject类:
package com.vslimit.kotlindemo.realmobj
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
/**
* Created by vslimit on 17/2/4.
*/
@RealmClass
open class Book : RealmObject(){
@PrimaryKey
open var id:String? = ""
open var name:String? = ""
open var author:String? = ""
}
配置 Realm
首先要在App中添加:
Realm.init(this)
RealmConfiguration 用来配置要被创建的 Realm 的各种特性。最简配置如下所示:
RealmConfiguration config = new RealmConfiguration.Builder().build();
如上配置的 Realm 会被存储在 Context.getFilesDir() 并且命名为 default.realm。
我在项目中定义了一个RealmUtil
package com.vslimit.kotlindemo.util.realm
import io.realm.Realm
import io.realm.RealmConfiguration
/**
* Created by vslimit on 16/11/8.
*/
class RealmUtil() {
companion object {
fun instant(): Realm {
val config = RealmConfiguration.Builder().name("myrealm.realm").schemaVersion(1).migration(Migration.getInstance()).build()
return Realm.getInstance(config)
}
}
}
数据库名字为myrealm;
请务必注意到Realm的实例是线程单例化的,也就是说,在同一个线程内多次调用静态方法获得针对同路径的Realm,会返回同一个Realm实例。
如果在项目初始化的时候,需要初始化部分数据,则可以将先将数据插入到myrealm中,然后用将myrealm.realm放到assets文件夹下,配置realm时加上assetFile("myrealm.realm"),具体代码如下:
val config = RealmConfiguration.Builder().name("myrealm.realm").schemaVersion(2).migration(Migration.getInstance()).assetFile("myrealm.realm").build()
迁移
所有数据库都要处理模型改变的情况。Realm 的数据模型用标准 Java 对象来定义,改变数据模型只需要改变数据对象定义即可。
如果没有旧 Realm 数据文件存在,那么代码的改变即会反应到相应的 Realm 数据文件改变。但如果已经有旧版本的 Realm 数据文件存在,Realm 会抛出异常提示数据库文件需要迁移。请在相应的 RealmConfiguration 设置 schema 版本和 migration 代码来正确处理并避免该异常抛出;
这里定义了一个Migrate,不过目前是空的:
package com.vslimit.kotlindemo.util.realm;
import io.realm.DynamicRealm;
import io.realm.RealmMigration;
import io.realm.RealmSchema;
/**
* Created by vslimit on 17/1/23.
*/
public class Migration implements RealmMigration {
private static Migration instance = null;
static {
instance = new Migration();
}
private Migration() {
}
public static Migration getInstance() {
return instance;
}
@Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema = realm.getSchema();
if (oldVersion == 0) {
oldVersion++;
}
// if (oldVersion == 1) {
// oldVersion++;
// }
}
}
对Realm扩展类RealmExtensions.kt:
package com.vslimit.kotlindemo.extensions
import io.realm.Realm
import io.realm.RealmObject
import io.realm.RealmQuery
import io.realm.RealmResults
/**
* Created by Kittinun Vantasin on 10/20/14.
*/
fun <T : RealmObject> Realm.create(clazz: Class<T>, f: (it: T) -> Unit): T {
beginTransaction()
val realmObject = createObject(clazz)
f(realmObject)
commitTransaction()
return realmObject
}
fun <T : RealmObject> Realm.create(it: T): T {
beginTransaction()
val realmObject = copyToRealm(it)
commitTransaction()
return realmObject
}
fun <T : RealmObject> Realm.createOrUpdate(it: T): T {
beginTransaction()
val realmObject = copyToRealmOrUpdate(it)
commitTransaction()
return realmObject
}
fun <T : RealmObject> Realm.deleteAll(clazz: Class<T>) {
beginTransaction()
val results = where(clazz).findAll()
results.deleteAllFromRealm()
commitTransaction()
}
fun <T : RealmObject> Realm.delete(clazz: Class<T>, key: String, value: String) {
beginTransaction()
val results = where(clazz).equalTo(key, value).findAll()
results.deleteAllFromRealm()
commitTransaction()
}
fun <T : RealmObject> Realm.query(clazz: Class<T>, conditionMap: Map<String, String>?): RealmResults<T> {
val query: RealmQuery<T> = where(clazz)
if (conditionMap != null) {
for ((key, value) in conditionMap) {
query.equalTo(key, value)
}
}
return query.findAll()
}
fun <T : RealmObject> Realm.show(clazz: Class<T>,conditionMap: Map<String, String>?): T {
val query: RealmQuery<T> = where(clazz)
if (conditionMap != null) {
for ((key, value) in conditionMap) {
query.equalTo(key, value)
}
}
return query.findFirst()
}
fun <T : RealmObject> Realm.findAll(clazz: Class<T>): RealmResults<T> {
return query(clazz, null)
}
下面我们来看看实际demo,布局代码还是之前的一个Textview和三个Button;
package com.vslimit.kotlindemo.fragment
import android.os.Bundle
import android.util.Log
import android.view.View
import com.vslimit.kotlindemo.R
import com.vslimit.kotlindemo.extensions.*
import com.vslimit.kotlindemo.realmobj.Book
import com.vslimit.kotlindemo.util.realm.RealmUtil
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_companys.*
import org.jetbrains.anko.async
import org.jetbrains.anko.onClick
import java.util.*
import kotlin.properties.Delegates
/**
* Created by vslimit on 16/12/31.
*/
class BookListFragment : BaseFragment() {
override val layoutResourceId: Int = R.layout.fragment_companys
var realm: Realm by Delegates.notNull()
companion object {
fun getInstance(): BookListFragment {
return BookListFragment()
}
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
init()
showBtn.onClick {
val book = realm.show(Book::class.java, mapOf("author" to "vslimit"))
Log.d("BOOK:::", book.name)
val name = book.name
async() { nameTv.text = name }
}
updateBtn.onClick {
val book = realm.show(Book::class.java, mapOf("author" to "vslimit"))
book.name = "update name"
realm.createOrUpdate(book)
}
insertBtn.onClick {
val book = Book()
book.id = UUID.randomUUID().toString()
book.name = "Kotlin Realm Android"
book.author = "vslimit"
realm.create(book)
}
}
override fun onResume() {
super.onResume()
realm.close()
}
fun init() {
realm = RealmUtil.instant()
val results = realm.findAll(Book::class.java)
val sizeTxt = "BOOK SIZE:${results.size}"
async() {
nameTv.text = sizeTxt
}
}
override fun onDestroy() {
super.onDestroy()
}
}
这里需要注意的
请谨记:Realm、RealmObject 和RealmResults 实例都不可以跨线程使用。
本文只是对Kotlin集成Realm做了简单的介绍,更多的内容,请查看官方文档:传送门
最后引用官方的一句话:
Realm 完全兼容 Kotlin 语言,但有些地方需要注意:
- 你的模型类需要是开放的(open)。
- 你可能需要在某些情况下添加注解 @RealmCLass 以保证编译通过。这是由于当前 Kotlin 注解处理器的一个限制。
- 很多 Realm API 引用了 Java 类。你必须在编译依赖中添加 org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}。
本文中的所有代码已经提交到git上了,大家如果喜欢就去git下star下吧。
Realm的代码详见:https://github.com/vslimit/kotlindemo