ActiveAndroidとは、アクティブ・レコードパターンのAndroidのORMです。
結構好きなので公式Wikiを和訳しました。
Getting started
Adding the JAR
jarを取得してプロジェクトにビルドパスを通す。
- ソースをcloneしてルートフォルダでantコマンドを実行する。成果物はdistフォルダに作成される。
- Downloadsから最新のjarをダウンロードしてくる
Installing from Maven
Gitからソースをcloneしてローカルのmavenリポジトリにインストールする。
- git clone https://github.com/pardom/ActiveAndroid.git
- cd ActiveAndroid
- mvn clean install
pomにdependencyを追加。
<dependency>
<groupId>com.activeandroid</groupId>
<artifactId>activeandroid</artifactId>
<version>(insert latest version)</version>
</dependency>
Configuring your project
ActiveAndroidをアプリケーションで使用する為には、AndroidManifest.xmlに設定を追加する。
下記オプションを追加する。
- AA_DB_NAME
- AA_DB_VERSION(デフォルトは1)
<manifest>
<application android:name="com.activeandroid.app.Application" ...>
...
<meta-data android:name="AA_DB_NAME" android:value="Pickrand.db" />
<meta-data android:name="AA_DB_VERSION" android:value="5" />
</application>
</manifest>
もしくは、コード内で指定する事も可能である。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Builder builder = new Configuration.Builder(getBaseContext());
builder.setDatabaseName("test.db");
builder.setDatabaseVersion(1);
ActiveAndroid.initialize(builder.create());
}
@Override
public void onTerminate() {
super.onTerminate();
ActiveAndroid.dispose();
}
ActiveAndroidを使用する為には、アプリケーションのエンドポイントをActiveAndroidのApplicationクラスにする事。
既に独自のApplicationクラスを作成していた場合は、com.activeandroid.app.Application
を継承するかinitializeメソッドとdisposeメソッドをコールする事。
public class MyApplication extends com.activeandroid.app.Application { ...
public class MyApplication extends SomeLibraryApplication {
@Override
public void onCreate() {
super.onCreate();
ActiveAndroid.initialize(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ActiveAndroid.dispose();
}
}
Creating your database model
データベースモデルの作成は簡単です。プロパティのアノテーションの引数に対応するカラム名が作成されます。
モデルを作成する為には、クラスがModelクラスを継承する必要がある事と、クラスに@Tableアノテーション、メンバに@Columnアノテーションを付与する必要がある事を覚えておいてください。
各アノテーションのオプションは下記の様になります。
定義先 | 定義内容 | 意味 |
---|---|---|
@Table | name | 対応するテーブル名 |
@Column | name | 対応するカラム名 |
length | 長さの制約(デフォルト -1(無制限?)) | |
notNull | not null制約(デフォルト false) | |
onNullConflict | null制約違反時の動作を設定する(デフォルトはFAIL, 設定内容はAndroid公式参照) | |
onDelete | 削除時の外部キーの動作設定(CASCADE, RESTRICT等が設定可能) | |
onUpdate | 更新時の外部キーの動作設定(CASCADE, RESTRICT等が設定可能) | |
unique | ユニーク制約(デフォルト false) | |
onUniqueConflict | ユニーク制約違反時の動作を設定\n(デフォルトはFAIL, 設定内容はAndroid公式参照) |
###コンストラクタ
ActiveAndroidは、オブジェクトをインスタンス化する際の標準的なコンストラクタを使用しています。
@Table(name = "Items")
public class Item extends Model {
@Column(name = "Name")
public String name;
@Column(name = "Category")
public Category category;
public Item(){
super();
}
public Item(String name, Category category){
super();
this.name = name;
this.category = category;
}
}
Relationships
ActiveAndroidではどの様にしてリレーションを実現するのでしょうか?
Itemクラスではメンバに直接Categoryを追加します。
@Table(name = "Items")
public class Item extends Model {
@Column(name = "Name")
public String name;
@Column(name = "Category")
public Category category;
}
CategoryクラスではヘルパーメソッドのgetManyを使用して1対多のリレーションを実現します。
@Table(name = "Categories")
public class Category extends Model {
@Column(name = "Name")
public String name;
public List<Item> items() {
return getMany(Item.class, "Category");
}
}
Saving to the database
挿入と更新
Category restaurants = new Category();
restaurants.name = "Restaurants";
restaurants.save();
リレーションがある場合
Item item = new Item();
item.category = restaurants;
item.name = "Outback Steakhouse";
item.save();
Bulk insert
約100倍に高速化できるとの事。
ActiveAndroid.beginTransaction();
try {
for (int i = 0; i < 100; i++) {
Item item = new Item();
item.name = "Example " + i;
item.save();
}
ActiveAndroid.setTransactionSuccessful();
}
finally {
ActiveAndroid.endTransaction();
}
Deleting records
3種類の方法を提供しています。
Item item = Item.load(Item.class, 1);
item.delete();
Item.delete(Item.class, 1);
new Delete().from(Item.class).where("Id = ?", 1).execute();
Querying the database
ActiveAndroidのクエリはBuilderパターンかModel#queryメソッドを使用して構築されます。
Itemモデルを例に考えてみましょう。
@Table(name = "Items")
public class Item extends Model {
@Column(name = "Name")
public String name;
@Column(name = "Category")
public Category category;
}
Itemから1件ランダムに取得したい場合は下記の様に記述します。
public static Item getRandom() {
return new Select().from(Item.class).orderBy("RANDOM()").executeSingle();
}
カテゴリに紐づくItem1件を取得したい場合は下記の様に記述します。
public static Item getRandom(Category category) {
return new Select()
.from(Item.class)
.where("Category = ?", category.getId())
.orderBy("RANDOM()")
.executeSingle();
}
カテゴリに紐づく全てのアイテムを取得したい場合は下記の様に記述します。
public static List<Item> getAll(Category category) {
return new Select()
.from(Item.class)
.where("Category = ?", category.getId())
.orderBy("Name ASC")
.execute();
.executeSingle();
}
Type serializers
ActiveAndroidはデフォルトで様々なクラスをサポートしていますが、サポート外のオブジェクトを扱う場合はTypeSerializerクラスを拡張したクラスを作成します。
TypeSerializerクラスを扱う上でベストな方法はソースコードを読む事です!ここではDate型を考えてみましょう。
TypeSerializerを作成する時に考える事は、いかにしてオブジェクトをActiveAndroidがサポートしている基本型に落としこむかという事です。
DateはLong型に変換できるので、Long型を使用してみましょう。
final public class UtilDateSerializer extends TypeSerializer {
@Override
public Class<?> getDeserializedType() {
return Date.class;
}
@Override
public Class<?> getSerializedType() {
return Long.class;
}
@Override
public Long serialize(Object data) {
if (data == null) {
return null;
}
return ((Date) data).getTime();
}
@Override
public Date deserialize(Object data) {
if (data == null) {
return null;
}
return new Date((Long) data);
}
}
まず、getDeserializedType
を確認します。このメソッドではシリアライズしようとしているクラスのクラスオブジェクトを返却します。
Date型の場合はDate.classを返却します。
次のメソッド(getSerializedType
)は逆の、つまり我々がデータベースに格納したい型を確認します。リテラル型が返却される事を期待するよりもむしろ、enumを選択してください。
このメソッドでは下記のenumを使用する事ができます。
public enum SQLiteType {
INTEGER, REAL, TEXT, BLOB
}
次のメソッド(serialize
)でActiveAndroidがサポートしている型に変換を行います。ここではDate型をLong型にキャストする為にgetDateメソッドを使用しています。
最後のメソッド(serialize
)ではデータベースのデータを我々が期待する型に変換します。ここではLong型からDate型へのキャストを実施しています。
あなたが作成したTypeSerializerを使用する為には、AndroidManifest.xmlで宣言する必要があります。
<meta-data android:name="AA_SERIALIZERS"
android:value="my.package.CustomTypeSerializer,my.package.AnotherCustomeTypeSerializer" />
Using the content provider
bq. このコードを動作させる際は、ここで指定したデフォルトのID列をオーバーライドする必要があります。
mySpinner.setAdapter(new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_expandable_list_item_1,
null,
new String[] { "MyProperty" },
new int[] { android.R.id.text1 },
0));
getActivity().getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle cursor) {
return new CursorLoader(getActivity(),
ContentProvider.createUri(MyEntityClass.class, null),
null, null, null, null
);
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
((SimpleCursorAdapter)mySpinner.getAdapter()).swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
((SimpleCursorAdapter)mySpinner.getAdapter()).swapCursor(null);
}
});
Schema migrations
新しいクラスが追加された際、ActiveAndroidはデフォルトでデータベースにテーブルを追加します。
既存のテーブルに変更を加える際には、assets/migrations
に配置したsqlスクリプトを実行する事で実現します。
手順
- ConfigurationクラスかAndroidManifest.xmlのAA_DB_VERSIONをインクリメントします。
- .sqlを
/assets/migrations
に配置します。
ActiveAndoridは既存のDBバージョン番号から新しいバージョン番号までの範囲の数字と一致するファイル名のSQLを順番に実行します。
例えば、Items
テーブルにcolor
カラムを追加する場合には、AA_DB_VERSIONを2にインクリメントして2.sqlというファイルを配置します。
ALTER TABLE Items ADD COLUMN Color INTEGER;
Pre populated databases
事前データを準備したい場合はassets
ディレクトリにコピーを追加します。
データベースが正しくAndroid上で動作している事を確認するには次のステップを踏みます。
-
android_metadata
をセットアップします。 - 全てのプライマリキーフィールドの名前をIdという名前に変更します(標準のAndroidデータベースと同様に_idではなく)
Shipping with a database
coming soon…