公式サイト はこちら
公式サイトに記載があるように、ローカル データベースにデータを保存する場合は、「 Room を使用することを強くおすすめします」とのことだったので、使ってみます。
使ってみて忘れないために本記事を残しておきたいと思います。
まずは公式ドキュメントを見て理解します。
Roomのアーキテクチャの図(公式より)
主要コンポーネント(公式より)
データベースクラス
データベースを保持し、アプリの永続データに対する基礎的な接続のメイン アクセスポイントとして機能します。
データエンティティ
アプリのデータベースのテーブルを表します。
データアクセスオブジェクト(DAO)
アプリがデータベースのデータのクエリ、更新、挿入、削除に使用できるメソッドを提供します。
なるほど…
…
……
私が Androidの公式ドキュメントを読んだだけで理解することは、ほぼないので実際に使ってみたいと思います。
サンプルコード
ライブラリのインポート
build.gradle の dependencies に記載。
build.gradle
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
テーブル構成
今回は、以下のような緯度経度が入った coordinates テーブルを作成していきます。
カラム名 | 型 | 内容 |
id | int | ID |
latitude | double | 緯度 |
longitude | double | 経度 |
created_at | String | 作成日 |
主要コンポーネント
コンポーネント | クラス名 | 役割 |
データベースクラス | AppData | アクセスポイント |
データエンティティ | Coordinate | テーブル構成 |
データアクセスオブジェクト(DAO) | CoordinateDao | データベースの操作、クエリ置き場のようなイメージ |
またデータの取得やインサートなどの操作を命令する CoordinateHelperクラス も作成します。
Database
entitiesの指定と、versionの指定などを行います。
見よう見まねで使っている感じが強いです。
AppData.java
@Database(entities = {Coordinate.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
//DAO用メソッド
public abstract CoordinateDao coordinateDao();
}
Entity
上述のテーブル構成はこちらに記載します。
テーブル名は、coordinates
プライマリーキーは id に設定しており、アノテーションを設定します。
autoGenerate は、インサート時に自動で生成されます。
auto_incrementと同じようなイメージでしょうか。
カラム名は特に指定がなければプロパティと同じになります。
ただし、カラム名はスネークケース、javaではプロパティ名をキャメルケースで書くのが一般的と思いますので、カラム名とプロパティ名を分けたい場合は、 ColumnInfo で設定します。
Coordinate.java
@Entity(tableName = "coordinates")
public class Coordinate {
/**
* 定義するカラム
*/
@PrimaryKey(autoGenerate = true)
public int id;
public double latitude;
public double longitude;
// カラム名とプロパティ名が異なる場合は、ColumnInfoで設定する
@ColumnInfo(name = "created_at")
public String createdAt;
/**
* コンストラクタ
* @param latitude 緯度
* @param longitude 経度
* @param createdAt 日付
*/
public Coordinate(double latitude, double longitude, String createdAt) {
this.latitude = latitude;
this.longitude = longitude;
this.createdAt = createdAt;
}
public int getId() {
return this.id;
}
public double getLatitude() {
return this.latitude;
}
public double getLongitude() {
return this.longitude;
}
public String getCreatedAt() {
return this.createdAt;
}
}
DAO
上述しましたが、クエリ置き場のようなイメージです。
insert、update、deleteはアノテーションさえ付ければsql文を書く必要がありません。
CoordinateDao.java
@Dao
public interface CoordinateDao {
/**
* 全データを昇順で取得
* @return リスト
*/
@Query("SELECT * FROM coordinates ORDER BY id ASC")
List<Coordinate> getCoordinateList();
/**
* データを追加
* @param coordinate 新規データ
*/
@Insert
void insert(Coordinate coordinate);
/**
* データを更新
* @param coordinate 更新データ
*/
@Update
void update(Coordinate coordinate);
/**
* データを削除
* @param coordinate 削除データ
*/
@Delete
void delete(Coordinate coordinate);
}
命令を下すHelperクラス
Roomでは、メインスレッドでクエリを発行しようとするとエラーを吐きますので、別スレッド(非同期処理)で行う必要があります。
サンプルでは、ExecutorService を利用しています。
CoordinateHelper.java
public class CoordinateHelper {
public static final String DB_NAME = "coordinate.db";
private final CoordinateDao mDao;
private List<Coordinate> mCoordinateList;
/**
* コンストラクタ
*/
public CoordinateHelper(Context context) {
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, DB_NAME).build();
mDao = db.coordinateDao();
}
/**
* DBからデータ取得してセット
*/
public void setCoordinateLocationList() {
// Roomは非同期でアクセスしないと、エラーを出すので注意
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
try {
mCoordinateList = mDao.getCoordinateList();
// UI変更など
} catch (Exception e) {
// エラー処理
}
}
});
}
/**
* DBへデータ追加
*/
public void insert(Coordinate coordinate){
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
try {
mDao.insert(coordinate);
} catch (Exception e) {
// エラー処理
}
}
});
}
/**
* DBのデータを削除
*/
public void delete(Coordinate coordinate){
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
try {
mDao.delete(coordinate);
} catch (Exception e) {
// エラー処理
}
}
});
}
}
アクティビティから呼び出し
データの追加例です。
Coordinateオブジェクトを生成して、命令を下すHelperオブジェクトにデータベースにデータを追加してもらっています。
SampleActivity.java
Coordinate coordinate = new Coordinate(latitude, longitude, createdAt);
CoordinateHelper coordinateHelper = new CoordinateHelper(context);
coordinateHelper.insert(coordinate); // データの追加
感想
軽く触ってみた感じだと、結構簡単にデータ操作が行えたなっていう印象ですね。
非同期処理が強いられるので、クエリ後の結果を使って操作する部分は、初学者にとっては難しそうだと感じました。
強くおすすめしているぐらいなので、これからはRoomを使うのが当たり前になるのでしょうか。