Android
SQLite3

SQLite3にJSONテキストで保存したカラムのデータを扱う for Android

@eaglesakura です。

Androidで大量のデータを扱う場合、SQLite3を使うことが多いかと思います(Realm を始めとした別なソリューションもあるので、必ず使うわけでは無いですが)。

データを保存する場合、大体はデータごとにカラムを整理し、分けて保存します。ですが、たまに「JSONでとりあえず突っ込んどこう」みたいな気分になるときがありますね(あるよね?)。

そんな時に、実装の選択肢の一つとして使えるかと思います。


AndroidのSQLite事情

Androidでは SQLite3 が標準で採用されていますが、細かいバージョンには差異があり、公式ドキュメントにまとまっています。ですが細かい差異はあっても、基本的に使える機能は一緒です。

Android API
SQLite Version

API 24
3.9

API 21
3.8

API 11
3.7

API 8
3.6

API 3
3.5

API 1
3.4


SQLite3でJSON型がサポートされた

最近のバージョンで、JSON型がサポートされました( https://www.sqlite.org/json1.html )。これにより、構造化されたデータの扱いや拡張が大幅に楽になるというメリットがあります(速度とか細かいことはとりあえず置いときます)。

「JSON型がサポートされた」とは言っても、JSON形式の文字列がカラムにガッツリと入っているだけで、特別な要素は特にありません。ただし、標準のSQLiteではJSON全体を1つの文字列として扱えませんが、JSONサポートによって構造化したデータとしてSELECTやWHERE等で参照できるようになりました。

例えば、次のように書くことでJSON文字列で保存された値をSELECTすることができます。

細かいところは別な解説記事( http://qiita.com/smith/items/c0bd002666a23a6fe8e4 )や公式ドキュメントを参照してください。

-- CENTRAL_JSONというカラムに入っているJSONデータから値をSELECTする

SELECT
DATE,
SESSION_ID,
json_extract(CENTRAL_JSON, "$.sensor.location.latitude") as json_number,
json_extract(CENTRAL_JSON, "$.sensor.location.longitude") as json_number
FROM
DB_SESSION_POINT


SQLite Android Bindingsを利用する

Android SDKでサポートされているSQLite3は機種ごとに固定バージョンであり、かつJSONサポートは拡張機能の扱いなので標準では利用できません。

そこで、SQLite3が公式で用意してくれている SQLite Android Bindings を利用します。

このライブラリはAndroid SDK標準のAPIとpackage名のみが違うクラス群を提供しており、かつSQLiteのバージョンを任意に変更できます。

下記にビルド済みバージョンを用意しましたので、自由に使って構いません。

ここではSQLite3のバージョンを 3.16.1 でビルドしました。

このリポジトリではデフォルトオプションでビルドしていますが、ビルドオプションを変更すればEncrypt Extension等の有用な機能を利用できます。

https://github.com/eaglesakura/android-sqliteX

// build.gradle

repositories {
// add maven repository
maven { url "http://eaglesakura.github.io/maven/" }
}

dependencies {
// add library
compile 'com.eaglesakura:android-sqliteX:3.16.1.+'
}


Android SDK組み込みのSQLite3からの移行

Java側では、利用するクラスのpackage名を次のように変更してください。

package名以外は基本的に同じインターフェースが提供されています。

ただし、自前でビルドした共有ライブラリをロードする必要がありますので、 System.loadLibrary("sqliteX") をコールするか、初期化時に org.sqlite.database.SQLiteX.install(Context) を実行してください。

標準 SQLite3
SQLiteX

package名変更
android.database.sqlite
org.sqlite.database.sqlite

初期化
-
org.sqlite.database.SQLiteX.install(context);

データベースファイル自体には互換性があり、カラムの型も TEXT のままで利用できます(少なくともSELECTは可能でした)。SQLiteにはカラムの厳密な型がなく、すべてテキストで保持しているため、あまり気にしなくて良いです。


ORマッパーとの相性

ORマッパーを利用している場合、android.database.sqlite.SQLiteDatabase クラスを直接参照している場合があります。その場合、組み込みのSQLiteを使うことを強制されていますので、拡張機能を使うことはできません。

greenDao 3 のように、抽象化されたアクセスを提供している場合は問題なく使えるかと思います。