LoginSignup
3

More than 1 year has passed since last update.

Realmの使い方 🔰初心者向け Kotlin

Last updated at Posted at 2020-12-10

最初に

この度初めて記事を投稿させていただきます。分りにくい箇所がありましたら気軽に質問してください。
今回は軽量かつ高速なデータベースRealmを紹介していきたいと思います。
バージョンは7.0.0と6.0.2を扱っていきたいと思います。
大した違いはないのでお好きなほうをどうぞ^^

■環境
・Android Studio 4.1.1
・Kotlin 1.4.10
・Realm 6.0.2 & 7.0.0

■公式サイト
Realm

インストール

build.gradle(アプリ名)【6.0.2】
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:6.0.2"
    }
}
build.gradle(アプリ名)【7.0.0】
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:7.0.0"
    }
}
build.grable(app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
build.grable(app)
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(アプリ名)に手を加える必要があります。

build.gradle(app)
buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
}
setting.gradle(アプリ名)
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と同じフォルダの中に作ります。

CustomApplication.kt

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に新たにコードを書いていきます。

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モデルを作っていきます。

Data(任意の名前).kt
open class Data : RealmObject() {
    @PrimaryKey
    var id: Int = 0
    @Required
    var text: String = ""
}

※openを忘れないでください
@PrimaryKeyは主キーでデータを一意に識別するために使われる項目、
@Requiredは入力が必須である(null×)項目です。

実際にDBを操作する

MainActivityに変更を加えていきます。

MainActivity.kt
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: RealmRealmを初期化してRealm.getDefaultInstance()で
先ほど作ったCustomApplication.ktから初期設定を読み込んでいます。
最後のonDestory()でRealmを閉じています。これがないとクラッシュします。

データの挿入(登録)

MainActivity.kt
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()}")
    }

    //省略

}
Logcast
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は下のタブにあります

データの検索

MainActivity.kt
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())
    }

    //省略

}
Logcast
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("フィールド名", "値")
:指定した値を含む文字列を含むデータを抽出する

データの更新

MainActivity.kt
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()}")
    }

    //省略

}
Logcast
E/RealmUpdate: updateRealm:Data = proxy[{id:1},{text:サンプルテキスト1}]

データの検索と手順は最初は同じです。検索したデータに?.フィールド名または!!.フィールド名を後ろにつけて更新したいデータを代入します。ただし、上記のようにさいごのfindの部分を.findFirst()で記述するときはとくに心配しなくても大丈夫ですが、.findAll()を使うときは、下記にように記述しないといけません。

MainActivity.kt
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()}")
}

データの削除

MainActivity.kt
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()
    }

    //省略

}
Logcast
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をつかってみた。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3