Android
Kotlin
sqlite
squidb

AndroidのためのSquiDB

やっぱりアプリつくるとデータをどう持つか考える必要がありますね。Androidアプリの内部DBにデータを持つことにしたので、SQLiteのライブラリとしてSquidDBを使ってみました。バージョンは3.2.3です。

設定

app/build.gradleにSquidDBを追加します。プロジェクト全体のbuild.gradleではないのでご注意を。

ついでにInjectionも追加します。

build.gradle
apply plugin: 'kotlin-kapt'

dependencies {
    ...
    // squidb
    implementation "com.yahoo.squidb:squidb:3.2.3"
    implementation 'com.yahoo.squidb:squidb-annotations:3.2.3'
    implementation 'com.yahoo.squidb:squidb-android:3.2.3'
    kapt 'com.yahoo.squidb:squidb-processor:3.2.3'

    // injection
    compile "com.google.dagger:dagger:2.8"
    kapt "com.google.dagger:dagger-compiler:2.8"
}

テーブルスキーマの定義

Personテーブルの定義を作ります。ここで定義したclassName(Personのこと)が、他のクラスから参照されるクラス名になります。ビルドするとSquiDBがジェネレイトしてくれます。

PersonSpec.kt
package com.example.myfirstapp.database

import com.yahoo.squidb.annotations.ColumnSpec
import com.yahoo.squidb.annotations.TableModelSpec

@TableModelSpec(className="Person", tableName="people")
class PersonSpec {
    private val firstName : String? = null

    private val lastName : String? = null

    @ColumnSpec(name = "creationDate")
    private val birthday : Long = 0
}

使える属性

使える属性は次のとおりです。意外なことにDate型は使えません。

  • Long
  • Integer
  • String
  • Boolean
  • Double
  • byte[] (Blob)

データベース設定

SquidDatabaseを継承して、データベース全体の定義を行います。
createOpenHelperがちょっとめんどうです。今回はこのクラスを利用する際にコンストラクタとしてcontextを追加することにします。

MyDatabase.kt
package com.example.myfirstapp.database

import android.content.Context
import com.yahoo.squidb.android.AndroidOpenHelper
import com.yahoo.squidb.data.ISQLiteDatabase
import com.yahoo.squidb.data.ISQLiteOpenHelper
import com.yahoo.squidb.data.SquidDatabase
import com.yahoo.squidb.sql.Table
import com.example.myfirstapp.database.Person

import javax.inject.Inject

class MyDatabase @Inject constructor(private  val context: Context): SquidDatabase(){
    val VERSION : Int = 1
    val NAME : String = "my-database.db"

    override fun getName(): String {
        return NAME
    }

    override fun getTables(): Array<Table> {
        return arrayOf(Person.TABLE)
    }

    override fun onUpgrade(db: ISQLiteDatabase?, oldVersion: Int, newVersion: Int): Boolean {
        return false
    }

    override fun getVersion(): Int {
        return VERSION
    }

    override fun createOpenHelper(databaseName: String?, delegate: OpenHelperDelegate?, version: Int): ISQLiteOpenHelper? {
        return AndroidOpenHelper(context,name,delegate,version)
    }

}

挿入する

これでデータベースをする準備ができました。さっそくレコードを追加してみましょう。適当なActivity上でやってみます。

val db: MyDatabase = MyDatabase(this)
val p: Person = Person()
p.firstName = "Sam"
p.lastName = "Bosley"
p.birthday = System.currentTimeMillis()
db.persist(p)

persistを実行したあとは、 p.id が設定されています。

クエリーを組み立てる

「select * from person where filest_name = "Sam"」的なクエリーです。=の他にも、>, <, and, or, join, order by, limit, offsetなどができます。

val q: Query = Query.select().where(Person.FIRST_NAME.eq("Sam"))

検索する

取得結果が複数ある場合の検索です。

val cursor: SquidCursor<Person> = db.query(Person::class.java, q)
try{
    val selectedPerson : Person = Person()
    while(cursor.moveToNext()){
       selectedPerson.readPropertiesFromCursor(cursor)
       // 検索結果を使った処理
    }
}finally {
    cursor.close()
}

取得結果が1件しかないとか、先頭1件だけつかうときはこっちでOK。

val person = db.fetchByQuery(Person::class.java, q)

更新する

1レコードだけ更新するやり方は、挿入とほぼ同じです。内部にセットされているIDを使って更新されます。

person.firstName = "Samuel"
db.persist(person)

詳細は割愛しますが、条件文を使って複数レコードを一度に更新することもできます。

削除する

削除は、IDをつかって行います。

db.delete(Person::class.java, person.id)

更新と同様に、条件文を使って複数レコードを一度に削除することもできます。

no such tableエラーになったら

アプリをエミュレータや実機で動かしていると、「no such table」エラーになる場合があります。アプリの初期インストールのときは自動的にテーブルが生成されますが、あとからテーブルを追加する場合は明示的に生成する必要があるためです。

もし(まだリリースしていない)開発中の場合だったら、エミュレータ上のアプリをアンインストールしましょう。

リリース後だったら、MyDatabaseでアップグレード時の処理を定義します。

カラム追加の場合も同様です。

MyDatabase.kt
    @Override
    protected int getVersion() {
        // これからリリースするアプリのバージョンが2
        return 2;
    }

    @Override
    protected boolean onUpgrade(ISQLiteDatabase db, int oldVersion, int newVersion) {
        switch(oldVersion) {
        case 1:
            // テーブルを追加する
            tryCreateTable(NewTable.TABLE);
        }
        return true;
    }

備考

公式ドキュメントの他に、こちらのレポジトリを参考にしました。
* kyryloz/android-budget-app
* vaibhavsonu/ModernAlarm