#最初に
この度初めて記事を投稿させていただきます。分りにくい箇所がありましたら気軽に質問してください。
今回は軽量かつ高速なデータベースRealmを紹介していきたいと思います。
バージョンは7.0.0と6.0.2を扱っていきたいと思います。
大した違いはないのでお好きなほうをどうぞ^^
■環境
・Android Studio 4.1.1
・Kotlin 1.4.10
・Realm 6.0.2 & 7.0.0
■公式サイト
Realm
インストール
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:6.0.2"
}
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:7.0.0"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
id 'realm-android'
}
※注意 pluginの順番は上記のようにしてください。
pluginの記述はどちらの方法でも構いません。
Android Studio 4.1.2 以降のjcenter()
廃止について
JCenter サービスの更新
2021年3月31日をもってjcenter()
が読み取り専用になったことにより、build.gradle(アプリ名)
のjcenter()
がmavenCentral()
へと変更されました。
しかし、Realmはjcenter()
にのみ対応しているためbuild.gradle(アプリ名)
に手を加える必要があります。
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
}
}
rootProject.name = "アプリ名"
include ':app'
上記のようにmavenCentral()
の下にjcenter()
を加えてください。
※注意 jcenter()
は非推奨なのでいつ使えなくなるかわからないためおすすめはしません。
また、setting.gradle
の2行目にあるrepositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
を
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
に変更してください。
Realmの初期化と設定
新しくCustomApplication.kt(ファイル名は自由)をMainActivityと同じフォルダの中に作ります。
class CustomApplication : Application() {
override fun onCreate() {
super.onCreate()
//初期化
Realm.init(this)
//設定
val config = RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
// .readOnly()
.build()
Realm.setDefaultConfiguration(config)
}
}
.deleteRealmIfMigrationNeeded()
はデータベース(DB)モデルを変更したときに必要に応じて、DBを削除・再構築してくれます。(DBを変更した後にこのコードがないとアプリがクラッシュします。)
.readOnly()
は導入していませんが、このコードを入れることでDBを読み込みのみにしてくれます。最初のうちは必要ないので、記述しなくても大丈夫です。
###Manifestファイルに登録
Realmを初期化して設定を読み込ませるためには、manifests/AndroidManifest.xmlに新たにコードを書いていきます。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.realmsampleqiita">
<application
android:name=".CustomApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--省略-->
</application>
</manifest>
<application>
の中にandroid:name=".CustomApplication"
を記述します。
#Modelの作成
続いてDBモデルを作っていきます。
open class Data : RealmObject() {
@PrimaryKey
var id: Int = 0
@Required
var text: String = ""
}
※open
を忘れないでください
@PrimaryKeyは主キーでデータを一意に識別するために使われる項目、
@Requiredは入力が必須である(null×)項目です。
#実際にDBを操作する
MainActivityに変更を加えていきます。
class MainActivity() : AppCompatActivity() {
private lateinit var realm: Realm
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
realm = Realm.getDefaultInstance()
}
override fun onDestroy() {
super.onDestroy()
realm.close()
}
}
private lateinit var realm: Realm
Realmを初期化してRealm.getDefaultInstance()
で
先ほど作ったCustomApplication.ktから初期設定を読み込んでいます。
最後のonDestory()
でRealmを閉じています。これがないとクラッシュします。
#データの挿入(登録)
class MainActivity() : AppCompatActivity() {
//省略
realm = Realm.getDefaultInstance()
insertData()
}
private fun insertData() {
realm.executeTransaction {
val id = realm.where<Data>().max("id")
val nextId1 = (id?.toLong() ?: 0) + 1
val realmObject1 = realm.createObject<Data>(nextId1)
realmObject1.text = "sampleText1"
val nextId2 = (id?.toLong() ?: 0) + 2
val realmObject2 = realm.createObject<Data>(nextId2)
realmObject2.text = "sampleText2"
val nextId3 = (id?.toLong() ?: 0) + 3
val realmObject3 = realm.createObject<Data>(nextId3)
realmObject3.text = "sampleText3"
}
Log.e("RealmInsert", "insertResult:${realm.where<Data>().findAll()}")
}
//省略
}
E/RealmInsert: insertResult:[Data = proxy[{id:1},{text:sampleText1}],
Data = proxy[{id:2},{text:sampleText2}],
Data = proxy[{id:3},{text:sampleText3}]]
realm.executeTransaction { }
はデータを書き込み・更新するときに必須になります。このコードを書かないと書き込み・更新ができません。
nextIdは登録ずみのidを検索してそのidに+1してidが被らないようにしています。
Logcast(Error)で登録したデータを確認できます。
Logcastは下のタブにあります
#データの検索
class MainActivity() : AppCompatActivity() {
//省略
realm = Realm.getDefaultInstance()
insertData()
selectData()
}
private fun selectData() {
val realmResult1 = realm.where<Data>().findAll()
val realmResult2 = realm.where<Data>().findFirst()
val realmResult3 = realm.where<Data>()
.equalTo("id", 1.toInt())
.findAll()
val realmResult4 = realm.where<Data>()
.equalTo("text", "sampleText2")
.findAll()
val realmResult5 = realm.where<Data>()
.greaterThan("id", 1)
.findAll()
val realmResult6 = realmResult1[1]?.text
Log.e("RealmSelect", """
|realmResult1:$realmResult1
|realmResult2:$realmResult2
|realmResult3:$realmResult3
|realmResult4:$realmResult4
|realmResult5:$realmResult5
|realmResult6:$realmResult6
|""".trimMargin())
}
//省略
}
E/RealmSelect: realmResult1:[Data = proxy[{id:1},{text:sampleText1}],
Data = proxy[{id:2},{text:sampleText2}],
Data = proxy[{id:3},{text:sampleText3}]]
realmResult2:Data = proxy[{id:1},{text:sampleText1}]
realmResult3:[Data = proxy[{id:1},{text:sampleText1}]]
realmResult4:[Data = proxy[{id:2},{text:sampleText2}]]
realmResult5:[Data = proxy[{id:2},{text:sampleText2}],
Data = proxy[{id:3},{text:sampleText3}]]
realmResult6:sampleText2
realm.where<Data>()
でデータを探し、そこから条件などを付けて取り出したいデータを検索します。データをすべて出したいときは.findAll()
を記述すればデータを取り出してくれます。.findFirst()
は条件下で一番最初のデータを取り出してくれます。
.eqoulTo()
のときだけ.toInt()
がついているのはコンパイラエラーを防ぐものです。
調べた限り修正方法は見当たらなかったので、公式が修正するまではこのままでしょう。
####条件コード一覧
.eqoulTo("フィールド名", 値)
:フィールドから値が同じデータを抽出する
.notEqoulTo("フィールド名", 値)
:フィールドから値が違うデータを抽出する
.greaterThan("フィールド名", 値)
:フィールドから指定した値より大きいデータを抽出する
.greaterThanOrEqualTo("フィールド名", 値)
:フィールドから指定した値以上のデータを抽出する
.lessThan("フィールド名", 値)
:フィールドから指定した値より小さいデータを抽出する
.lessThanOrEqualTo("フィールド名", 値)
:フィールドから指定した値以下のデータを抽出する
.beginsWith("フィールド名", "値")
:指定した値から始まる文字列を含むデータを抽出する
.endsWith("フィールド名", "値")
:指定した値で終わる文字列を含むデータを抽出する
.contains("フィールド名", "値")
:指定した値を含む文字列を含むデータを抽出する
データの更新
class MainActivity() : AppCompatActivity() {
//省略
realm = Realm.getDefaultInstance()
insertData()
selectData()
updateData()
}
private fun updateData() {
val data = realm.where<Data>()
.lessThanOrEqualTo("id",2)
.contains("text", "1")
.findFirst()
realm.executeTransaction {
data?.text = "サンプルテキスト1"
}
Log.e("RealmUpdate", "updateRealm:${realm.where<Data>().equalTo("id", 1.toInt()).findFirst()}")
}
//省略
}
E/RealmUpdate: updateRealm:Data = proxy[{id:1},{text:サンプルテキスト1}]
データの検索と手順は最初は同じです。検索したデータに?.フィールド名
または!!.フィールド名
を後ろにつけて更新したいデータを代入します。ただし、上記のようにさいごのfindの部分を.findFirst()
で記述するときはとくに心配しなくても大丈夫ですが、.findAll()
を使うときは、下記にように記述しないといけません。
private fun updateData() {
val data = realm.where<Data>()
.lessThanOrEqualTo("id",2)
.contains("text", "1")
.findAll()
realm.executeTransaction {
data[0]?.text = "サンプルテキスト1"
}
Log.e("RealmUpdate", "updateRealm:${realm.where<Data>().equalTo("id", 1.toInt()).findFirst()}")
}
データの削除
class MainActivity() : AppCompatActivity() {
//省略
realm = Realm.getDefaultInstance()
insertData()
selectData()
updateData()
deleteData()
}
private fun deleteData() {
realm.beginTransaction()
val target = realm.where<Data>().findAll()
target.deleteFromRealm(1)
Log.e("RealmDelete", "deletePartRealm:${realm.where<Data>().findAll()}")
target.deleteAllFromRealm()
Log.e("RealmDelete", "deleteAllRealm:${realm.where<Data>().findAll()}")
realm.commitTransaction()
}
//省略
}
E/RealmDelete: deletePartRealm:[Data = proxy[{id:1},{text:サンプルテキスト1}],
Data = proxy[{id:3},{text:sampleText3}]]
E/RealmDelete: deleteAllRealm:[]
今回はrealm.executeTransaction { }
の代わりにrealm.beginTransaction()
とrealm.commitTransaction()
を使いました。使い方は、データの書き込み・更新をするコードをbeginとcommitで挟むだけです。役割は前者と変わりません。
#最後に
今回の記事はどうでしたでしょうか?伝わりにくい場所があったかもしれませんが、RealmはSQLとは違ってKotlinで記述できるので簡単に導入できるのではないでしょうか。質問等ありましたら気軽にコメントください。
##参考文献
Realmの基本的な使い方まとめ in Kotlin
Kotlin + Realmでシンプルなメモ帳アプリを作ってみた
Kotlin + Android でRealmをつかってみた。