やっぱりアプリつくるとデータをどう持つか考える必要がありますね。Androidアプリの内部DBにデータを持つことにしたので、SQLiteのライブラリとしてSquidDBを使ってみました。バージョンは3.2.3です。
設定
app/build.gradleにSquidDBを追加します。プロジェクト全体のbuild.gradleではないのでご注意を。
ついでにInjectionも追加します。
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がジェネレイトしてくれます。
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を追加することにします。
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でアップグレード時の処理を定義します。
カラム追加の場合も同様です。
@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