Android
レルム
サーチ…
前書き
Realm Mobile DatabaseはSQLiteの代替品です。 Realm Mobile Databaseは、ORMよりもはるかに高速で、raw SQLiteよりも高速です。
利点
オフライン機能、高速クエリ、安全なスレッド化、クロスプラットフォームアプリケーション、暗号化、リアクティブアーキテクチャ。
備考
レルムを使用するときは、スレッド間でRealmObjects、RealmResults、およびRealmインスタンスを渡さないでください。特定のスレッドでクエリが必要な場合は、そのスレッドでRealmインスタンスを開きます。スレッドの終了時に、レルムを閉じる必要があります。
法律上の注意 :本ソフトウェアには輸出制限の対象となる暗号機能が含まれていることを理解しており、 キューバ、イラン、北朝鮮を含む米国の輸出制限または禁輸対象国に所在していないことを表明します スーダン、シリア、クリミア地域で 、拒否された人物、未確認の当事者、または制限付き団体と提携している商務省のリストに載っていないことを確認してください。
レルムをプロジェクトに追加する
プロジェクトレベルのbuild.gradle
ファイルに次の依存関係を追加します。
dependencies {
classpath "io.realm:realm-gradle-plugin:3.1.2"
}
アプリレベルのbuild.gradle
ファイルの上部に次の権限を追加します。
apply plugin: 'realm-android'
gradle syncを完了すると、レルムがプロジェクトに依存するようになりました!
Realmは2.0.0以降の初期呼び出しが必要です。これは、 Application
クラスまたは最初のアクティビティのonCreate
メソッドで行うことができます。
Realm.init(this); // added in Realm 2.0.0
Realm.setDefaultConfiguration(new RealmConfiguration.Builder().build());
レルムモデル
レルムモデルはRealmObject
ベースクラスを拡張する必要があり、基礎となるデータベースのスキーマを定義します。
サポートされるフィールドタイプは、 boolean
、 byte
、 short
、 int
、 long
、 float
、 double
、 String
、 Date
、 byte[]
、他のRealmObject
へのリンク、 RealmList<T extends RealmModel>
です。
public class Person extends RealmObject {
@PrimaryKey //primary key is also implicitly an @Index
//it is required for `copyToRealmOrUpdate()` to update the object.
private long id;
@Index //index makes queries faster on this field
@Required //prevents `null` value from being inserted
private String name;
private RealmList<Dog> dogs; //->many relationship to Dog
private Person spouse; //->one relationship to Person
@Ignore
private Calendar birthday; //calendars are not supported but can be ignored
// getters, setters
}
RealmObjectに新しいフィールドを追加(または削除)したり、新しいRealmObjectクラスを追加したり、既存のフィールドを削除すると、 移行が必要になります。あなたはどちらかに設定することができますdeleteIfMigrationNeeded()
あなたにRealmConfiguration.Builder
、または必要に応じて移行を定義します。 @Required
、 @Index
、または@PrimaryKey
アノテーションを追加(または削除)するときにも移行が必要です。
リレーションシップは手動で設定する必要があり、主キーに基づいて自動ではありません。
0.88.0以降、RealmObjectクラスのプライベートフィールド/ゲッター/セッターの代わりにパブリックフィールドを使用することもできます。
クラスに@RealmClass
も注釈が付けられている場合、 RealmObject
を拡張する代わりにRealmModel
を実装することもできます。
@RealmClass
public class Person implements RealmModel {
// ...
}
この場合、 person.deleteFromRealm()
やperson.addChangeListener()
などのメソッドは、 RealmObject.deleteFromRealm(person)
およびRealmObject.addChangeListener(person)
置き換えられます。
RealmObject
では、 RealmObject
のみをRealmObject
することができ、 final
フィールド、 volatile
transient
フィールドおよびtransient
フィールドはサポートされていないという制限があります。
管理対象の RealmObjectクラスは、トランザクション内でしか変更できないことが重要です。 マネージ RealmObjectはスレッド間で渡すことはできません。
プリミティブのリスト(RealmList )
レルムは現在、プリミティブのリストの格納をサポートしていません。それはそのToDoリスト( GitHub issue#575 )にありますが、その間に回避策があります。
プリミティブ型の新しいクラスを作成します。これはIntegerを使用しますが、保存するものは変更します。
public class RealmInteger extends RealmObject {
private int val;
public RealmInteger() {
}
public RealmInteger(int val) {
this.val = val;
}
// Getters and setters
}
これをRealmObject
使用できるようにRealmObject
。
public class MainObject extends RealmObject {
private String name;
private RealmList<RealmInteger> ints;
// Getters and setters
}
使用している場合はGSON
ご移入するRealmObject
、カスタムタイプのアダプタを追加する必要があります。
Type token = new TypeToken<RealmList<RealmInteger>>(){}.getType();
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.registerTypeAdapter(token, new TypeAdapter<RealmList<RealmInteger>>() {
@Override
public void write(JsonWriter out, RealmList<RealmInteger> value) throws IOException {
// Empty
}
@Override
public RealmList<RealmInteger> read(JsonReader in) throws IOException {
RealmList<RealmInteger> list = new RealmList<RealmInteger>();
in.beginArray();
while (in.hasNext()) {
list.add(new RealmInteger(in.nextInt()));
}
in.endArray();
return list;
}
})
.create();
リソースを試してみる
try (Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//whatever Transaction that has to be done
}
});
//No need to close realm in try-with-resources
}
試用リソースは、KITKAT(minSDK 19)からのみ使用できます。
並べ替えられたクエリ
クエリをソートするには、 findAll()
を使用する代わりに、 findAllSorted()
を使用する必要があります。
RealmResults<SomeObject> results = realm.where(SomeObject.class)
.findAllSorted("sortField", Sort.ASCENDING);
注意:
sort()
は、 sort()
たまったく新しいRealmResultsを返しますが、このRealmResultsの更新によってリセットされます。あなたが使用している場合はsort()
あなたは常にあなたにそれをソートし直す必要がありますRealmChangeListener
、削除RealmChangeListener
以前からRealmResults
と返された新しいに追加RealmResults
。まだロードされていない非同期クエリによって返されたRealmResults
sort()
を使用すると失敗します。
findAllSorted()
は更新されても、フィールドでソートされた結果を常に返します。 findAllSorted()
を使用することをお勧めします。
非同期クエリ
すべての同期クエリメソッド( findAll()
やfindAllSorted()
)には、非同期の対応( findAllAsync()
/ findAllSortedAsync()
)があります。
非同期クエリは、 RealmResults
の評価を別のスレッドにRealmResults
します。現在のスレッドでこれらの結果を受け取るには、現在のスレッドはルーパースレッドでなければなりません(read:非同期クエリは通常UIスレッドでのみ機能します)。
RealmChangeListener<RealmResults<SomeObject>> realmChangeListener; // field variable
realmChangeListener = new RealmChangeListener<RealmResults<SomeObject>>() {
@Override
public void onChange(RealmResults<SomeObject> element) {
// asyncResults are now loaded
adapter.updateData(element);
}
};
RealmResults<SomeObject> asyncResults = realm.where(SomeObject.class).findAllAsync();
asyncResults.addChangeListener(realmChangeListener);
RxJavaでレルムを使用する
クエリーの場合、RealmはrealmResults.asObservable()
メソッドを提供します。観察結果は、ルーパースレッド(通常はUIスレッド)でのみ可能です。
これを実行するには、構成に次のものが含まれている必要があります
realmConfiguration = new RealmConfiguration.Builder(context) //
.rxFactory(new RealmObservableFactory()) //
//...
.build();
その後、結果を観測可能なものとして使用することができます。
Observable<RealmResults<SomeObject>> observable = results.asObservable();
非同期クエリの場合は、クエリが実行されたときにのみイベントを受け取るように、 isLoaded()
で結果をフィルタリングする必要があります。このfilter()
は同期クエリには必要ありません( isLoaded()
常に同期クエリでtrue
を返しtrue
)。
Subscription subscription = RxTextView.textChanges(editText).switchMap(charSequence ->
realm.where(SomeObject.class)
.contains("searchField", charSequence.toString(), Case.INSENSITIVE)
.findAllAsync()
.asObservable())
.filter(RealmResults::isLoaded) //
.subscribe(objects -> adapter.updateData(objects));
書き込みの場合は、 executeTransactionAsync()
メソッドを使用するか、バックグラウンドスレッドでRealmインスタンスを開き、トランザクションを同期して実行してから、Realmインスタンスを閉じます。
public Subscription loadObjectsFromNetwork() {
return objectApi.getObjects()
.subscribeOn(Schedulers.io())
.subscribe(response -> {
try(Realm realmInstance = Realm.getDefaultInstance()) {
realmInstance.executeTransaction(realm -> realm.insertOrUpdate(response.objects));
}
});
}
基本的な使用法
インスタンスを設定する
レルムを使用するには、まずそのインスタンスを取得する必要があります。各Realmインスタンスは、ディスク上のファイルにマップされます。インスタンスを取得する最も基本的な方法は次のとおりです。
// Create configuration
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(context).build();
// Obtain realm instance
Realm realm = Realm.getInstance(realmConfiguration);
// or
Realm.setDefaultConfiguration(realmConfiguration);
Realm realm = Realm.getDefaultInstance();
Realm.getInstance()
メソッドは、作成されていない場合はデータベースファイルを作成し、それ以外の場合はファイルを開きます。 RealmConfiguration
オブジェクトは、 inMemory()
データベース、Realmファイルの名前、マイグレーションが必要な場合にレルムをクリアする必要があるかどうか、初期データなど、レルムの作成方法のすべての側面を制御します。
Realm.getInstance()
への呼び出しは参照カウントされ(各呼び出しはカウンタをインクリメントします)、 realm.close()
が呼び出されるとカウンタはデクリメントされることに注意してください。
インスタンスのクローズ
バックグラウンドスレッドでは、Realmインスタンスが使用されなくなると(たとえば、トランザクションが完了してスレッドの実行が終了するなど)、Realmインスタンスを閉じることが非常に重要です。バックグラウンドスレッドですべてのRealmインスタンスを閉じることができないと、バージョンが固定され、ファイルサイズが大幅に増加する可能性があります。
Runnable runnable = new Runnable() {
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
// ...
} finally {
if(realm != null) {
realm.close();
}
}
};
new Thread(runnable).start(); // background thread, like `doInBackground()` of AsyncTask
APIレベル19以上では、このコードを次のように置き換えることができます。
try(Realm realm = Realm.getDefaultInstance()) {
// ...
}
モデル
次のステップはあなたのモデルを作成することです。ここで、「モデルは何ですか?」という質問が出されることがあります。モデルは、データベースに格納されているオブジェクトのプロパティを定義する構造体です。例えば、以下では本をモデル化する。
public class Book extends RealmObject {
// Primary key of this entity
@PrimaryKey
private long id;
private String title;
@Index // faster queries
private String author;
// Standard getters & setter
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
モデルがRealmObjectクラスを拡張する必要があることに注意してください。主キーは@PrimaryKey
アノテーションによっても指定されます。主キーはnullでもかまいませんが、主キーとしてnull
を持つ要素は1つだけです。また、ディスクに永続化されるべきでないフィールドに@Ignore
アノテーションを使用することもできます:
@Ignore
private String isbn;
データの挿入または更新
ブックオブジェクトをRealmデータベースインスタンスに格納するには、まずモデルのインスタンスを作成してからcopyToRealm
メソッドを使用してデータベースに格納します。作成または更新するには、 copyToRealmOrUpdate
を使用できます。 (より速い代替手段は新しく追加されたinsertOrUpdate()
)。
// Creating an instance of the model
Book book = new Book();
book.setId(1);
book.setTitle("Walking on air");
book.setAuthor("Taylor Swift")
// Store to the database
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.insertOrUpdate(book);
}
});
データに対するすべての変更は、トランザクション内で行われなければならないことに注意してください。オブジェクトを作成する別の方法は、次のパターンを使用することです。
Book book = realm.createObject(Book.class, primaryKey);
...
データベースのクエリ
すべての書籍:
RealmResults<Book> results = realm.where(Book.class).findAll();
10以上のIDを持つすべての書籍:
RealmResults<Book> results = realm.where(Book.class) .greaterThan("id", 10) .findAll();
'Taylor Swift'
や'%Peter%'
書籍:RealmResults<Book> results = realm.where(Book.class) .beginGroup() .equalTo("author", "Taylor Swift") .or() .contains("author", "Peter") .endGroup().findAll();
オブジェクトの削除
たとえば、Taylor Swiftのすべての書籍を削除したいとします。
// Start of transaction
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
// First Step: Query all Taylor Swift books
RealmResults<Book> results = ...
// Second Step: Delete elements in Realm
results.deleteAllFromRealm();
}
});