Tip
このガイドでは Device Sync を使用しません
このガイドは、デバイス ローカル Realm を使い始めるのに役立ちます。 アプリケーションが、 Atlas Device Sync 、Realm Functions、またはユーザー管理などの機能を使用して、ネットワーク経由でバックエンド アプリと通信する必要がある場合は、「 同期を使用したクイック スタート 」のガイドに従う必要があります。
このページには、Realm をアプリにすばやく統合するための情報が含まれています。 始める前に、以下のものがあることを確認してください。
Realm の初期化
アプリで Realm を使用する前に、Realm ライブラリを初期化する必要があります。 アプリケーションは、アプリケーションを実行するたびに Realm を 1 回だけ初期化する必要があります。
Realmライブラリを初期化するには、context Realm.init()静的関数に Android を指定します。初期化用のアクティビティ、フラグメント、またはアプリケーションcontext を指定すると、動作に違いはありません。アプリケーションサブクラス の メソッドでRealmライブラリを初期化すると、アプリケーションを実行するたびにonCreate() Realm を初期化するたびに 1 回だけRealmを初期化するようになります。
Realm.init(this); // context, usually an Activity or Application
Realm.init(this) // context, usually an Activity or Application
Tip
Android マニフェストでのアプリケーション サブクラスの登録
独自のApplicationサブクラスを作成する場合は、カスタム アプリケーション ロジックを実行するためにアプリケーションのAndroidManifest.xmlにそれを追加する必要があります。 マニフェストのアプリケーション定義のandroid.nameプロパティを設定して、ユーザーがアプリケーションを起動したときに Android が他のクラスよりも先にApplicationサブクラスをインスタンス化するようにします。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mongodb.example"> <application android:name=".MyApplicationSubclass" ... /> </manifest>
オブジェクトモデルを定義する
アプリケーションのデータモデルは、Realm 内に保存されるデータの構造を定義します。 Realm オブジェクトモデルを使用すると、アプリケーション コード内の Kotlin または Java クラスを介してアプリケーションのデータモデルを定義できます。
アプリケーションのデータモデルを定義するには、次のクラス定義をアプリケーション コードに追加します。
import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; public class Task extends RealmObject { private String name; private String status = TaskStatus.Open.name(); public void setStatus(TaskStatus status) { this.status = status.name(); } public String getStatus() { return this.status; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Task(String _name) { this.name = _name; } public Task() {} }
public enum TaskStatus { Open("Open"), InProgress("In Progress"), Complete("Complete"); String displayName; TaskStatus(String displayName) { this.displayName = displayName; } }
enum class TaskStatus(val displayName: String) { Open("Open"), InProgress("In Progress"), Complete("Complete"), } open class Task() : RealmObject() { var name: String = "task" var status: String = TaskStatus.Open.name var statusEnum: TaskStatus get() { // because status is actually a String and another client could assign an invalid value, // default the status to "Open" if the status is unreadable return try { TaskStatus.valueOf(status) } catch (e: IllegalArgumentException) { TaskStatus.Open } } set(value) { status = value.name } }
Realm を開く
RealmConfigurationを使用して、Realm の名前や場所、UI スレッド上の Realm への同期読み取りまたは書込みを許可するかどうかなど、開く Realm の詳細を制御します。
String realmName = "My Project"; RealmConfiguration config = new RealmConfiguration.Builder().name(realmName).build(); Realm backgroundThreadRealm = Realm.getInstance(config);
val realmName: String = "My Project" val config = RealmConfiguration.Builder().name(realmName).build() val backgroundThreadRealm : Realm = Realm.getInstance(config)
オブジェクトの作成、読み取り、更新、削除
Realm を開くと、書込みトランザクション ( write transaction ) ブロックでその Realm 内の オブジェクト を変更できます。
重要
UI スレッドでの同期読み取りと書込み
デフォルトでは、非同期トランザクションを使用して、アプリケーションの UI スレッド内の Realm の読み取りまたは書き込みのみが可能です。 つまり、同期メソッドの使用を明示的に許可しない限り、Android アプリケーションのメイン スレッドでは、名前がAsyncという単語で終わるRealmメソッドのみを使用できます。
この制限はアプリケーション ユーザーのメリットのために存在します。UI スレッドで読み取りおよび書込み操作を実行すると、UI のインタラクションが応答しなくなったり低速になったりする可能性があるため、通常、これらの操作は非同期またはバックグラウンド スレッドで取り扱うことをお勧めします。 ただし、アプリケーションで同期 Realm の読み取りまたは UI スレッドでの書込みを使用する必要がある場合は、次のSyncConfigurationオプションを使用して同期メソッドの使用を明示的に許可できます。
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); } });
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread.") } })
新しいTaskを作成するには、 Taskクラスのインスタンスをインスタンス化し、それを書込みブロックの Realm に追加します。
Task Task = new Task("New Task"); backgroundThreadRealm.executeTransaction (transactionRealm -> { transactionRealm.insert(Task); });
val task : Task = Task() task.name = "New Task" backgroundThreadRealm.executeTransaction { transactionRealm -> transactionRealm.insert(task) }
Realm 内のすべてのアイテムのライブコレクションを取得できます。
// all Tasks in the realm RealmResults<Task> Tasks = backgroundThreadRealm.where(Task.class).findAll();
// all tasks in the realm val tasks : RealmResults<Task> = backgroundThreadRealm.where<Task>().findAll()
フィルターを使用してそのコレクションをフィルタリングすることもできます。
// you can also filter a collection RealmResults<Task> TasksThatBeginWithN = Tasks.where().beginsWith("name", "N").findAll(); RealmResults<Task> openTasks = Tasks.where().equalTo("status", TaskStatus.Open.name()).findAll();
// you can also filter a collection val tasksThatBeginWithN : List<Task> = tasks.where().beginsWith("name", "N").findAll() val openTasks : List<Task> = tasks.where().equalTo("status", TaskStatus.Open.name).findAll()
タスクを変更するには、書込みトランザクション ブロックでそのプロパティを更新します。
Task otherTask = Tasks.get(0); // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction( transactionRealm -> { Task innerOtherTask = transactionRealm.where(Task.class).equalTo("_id", otherTask.getName()).findFirst(); innerOtherTask.setStatus(TaskStatus.Complete); });
val otherTask: Task = tasks[0]!! // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction { transactionRealm -> val innerOtherTask : Task = transactionRealm.where<Task>().equalTo("name", otherTask.name).findFirst()!! innerOtherTask.status = TaskStatus.Complete.name }
最後に、書込みトランザクション ブロックでdeleteFromRealm()メソッドを呼び出すことでタスクを削除できます。
Task yetAnotherTask = Tasks.get(0); String yetAnotherTaskName = yetAnotherTask.getName(); // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction( transactionRealm -> { Task innerYetAnotherTask = transactionRealm.where(Task.class).equalTo("_id", yetAnotherTaskName).findFirst(); innerYetAnotherTask.deleteFromRealm(); });
val yetAnotherTask: Task = tasks.get(0)!! val yetAnotherTaskName: String = yetAnotherTask.name // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction { transactionRealm -> val innerYetAnotherTask : Task = transactionRealm.where<Task>().equalTo("name", yetAnotherTaskName).findFirst()!! innerYetAnotherTask.deleteFromRealm() }
変更の監視
addChangeListener()メソッドでカスタムOrderedRealmCollectionChangeListenerをアタッチすると、Realm、コレクション、またはオブジェクトの変更を監視できます。
// all Tasks in the realm RealmResults<Task> Tasks = uiThreadRealm.where(Task.class).findAllAsync(); Tasks.addChangeListener(new OrderedRealmCollectionChangeListener<RealmResults<Task>>() { public void onChange(RealmResults<Task> collection, OrderedCollectionChangeSet changeSet) { // process deletions in reverse order if maintaining parallel data structures so indices don't change as you iterate OrderedCollectionChangeSet.Range[] deletions = changeSet.getDeletionRanges(); for (OrderedCollectionChangeSet.Range range : deletions) { Log.v("QUICKSTART", "Deleted range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } OrderedCollectionChangeSet.Range[] insertions = changeSet.getInsertionRanges(); for (OrderedCollectionChangeSet.Range range : insertions) { Log.v("QUICKSTART", "Inserted range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } OrderedCollectionChangeSet.Range[] modifications = changeSet.getChangeRanges(); for (OrderedCollectionChangeSet.Range range : modifications) { Log.v("QUICKSTART", "Updated range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } } });
// all tasks in the realm val tasks : RealmResults<Task> = realm.where<Task>().findAllAsync() tasks.addChangeListener(OrderedRealmCollectionChangeListener<RealmResults<Task>> { collection, changeSet -> // process deletions in reverse order if maintaining parallel data structures so indices don't change as you iterate val deletions = changeSet.deletionRanges for (i in deletions.indices.reversed()) { val range = deletions[i] Log.v("QUICKSTART", "Deleted range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } val insertions = changeSet.insertionRanges for (range in insertions) { Log.v("QUICKSTART", "Inserted range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } val modifications = changeSet.changeRanges for (range in modifications) { Log.v("QUICKSTART", "Updated range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } })
完全な例
このプロジェクトを新しい Android Studio プロジェクトで実行している場合は、このファイルをコピーして、アプリケーションのMainActivityに貼り付けることができます。次の操作だけを忘れずに。
自分のプロジェクトのファイル上部でパッケージ宣言を使用する
Java を使用している場合は、
TaskとTaskStatusのimportステートメントを更新
import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; public class Task extends RealmObject { private String name; private String status = TaskStatus.Open.name(); public void setStatus(TaskStatus status) { this.status = status.name(); } public String getStatus() { return this.status; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Task(String _name) { this.name = _name; } public Task() {} }
public enum TaskStatus { Open("Open"), InProgress("In Progress"), Complete("Complete"); String displayName; TaskStatus(String displayName) { this.displayName = displayName; } }
import io.realm.OrderedCollectionChangeSet; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import io.realm.OrderedRealmCollectionChangeListener; import io.realm.Realm; import io.realm.RealmConfiguration; import io.realm.RealmResults; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import com.mongodb.realm.examples.model.java.Task; import com.mongodb.realm.examples.model.java.TaskStatus; public class MainActivity extends AppCompatActivity { Realm uiThreadRealm; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Realm.init(this); // context, usually an Activity or Application String realmName = "My Project"; RealmConfiguration config = new RealmConfiguration.Builder().name(realmName).build(); uiThreadRealm = Realm.getInstance(config); addChangeListenerToRealm(uiThreadRealm); FutureTask<String> Task = new FutureTask(new BackgroundQuickStart(), "test"); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.execute(Task); } private void addChangeListenerToRealm(Realm realm) { // all Tasks in the realm RealmResults<Task> Tasks = uiThreadRealm.where(Task.class).findAllAsync(); Tasks.addChangeListener(new OrderedRealmCollectionChangeListener<RealmResults<Task>>() { public void onChange(RealmResults<Task> collection, OrderedCollectionChangeSet changeSet) { // process deletions in reverse order if maintaining parallel data structures so indices don't change as you iterate OrderedCollectionChangeSet.Range[] deletions = changeSet.getDeletionRanges(); for (OrderedCollectionChangeSet.Range range : deletions) { Log.v("QUICKSTART", "Deleted range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } OrderedCollectionChangeSet.Range[] insertions = changeSet.getInsertionRanges(); for (OrderedCollectionChangeSet.Range range : insertions) { Log.v("QUICKSTART", "Inserted range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } OrderedCollectionChangeSet.Range[] modifications = changeSet.getChangeRanges(); for (OrderedCollectionChangeSet.Range range : modifications) { Log.v("QUICKSTART", "Updated range: " + range.startIndex + " to " + (range.startIndex + range.length - 1)); } } }); } protected void onDestroy() { super.onDestroy(); // the ui thread realm uses asynchronous transactions, so we can only safely close the realm // when the activity ends and we can safely assume that those transactions have completed uiThreadRealm.close(); } public class BackgroundQuickStart implements Runnable { public void run() { String realmName = "My Project"; RealmConfiguration config = new RealmConfiguration.Builder().name(realmName).build(); Realm backgroundThreadRealm = Realm.getInstance(config); Task Task = new Task("New Task"); backgroundThreadRealm.executeTransaction (transactionRealm -> { transactionRealm.insert(Task); }); // all Tasks in the realm RealmResults<Task> Tasks = backgroundThreadRealm.where(Task.class).findAll(); // you can also filter a collection RealmResults<Task> TasksThatBeginWithN = Tasks.where().beginsWith("name", "N").findAll(); RealmResults<Task> openTasks = Tasks.where().equalTo("status", TaskStatus.Open.name()).findAll(); Task otherTask = Tasks.get(0); // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction( transactionRealm -> { Task innerOtherTask = transactionRealm.where(Task.class).equalTo("_id", otherTask.getName()).findFirst(); innerOtherTask.setStatus(TaskStatus.Complete); }); Task yetAnotherTask = Tasks.get(0); String yetAnotherTaskName = yetAnotherTask.getName(); // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction( transactionRealm -> { Task innerYetAnotherTask = transactionRealm.where(Task.class).equalTo("_id", yetAnotherTaskName).findFirst(); innerYetAnotherTask.deleteFromRealm(); }); // because this background thread uses synchronous realm transactions, at this point all // transactions have completed and we can safely close the realm backgroundThreadRealm.close(); } } }
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import android.util.Log import io.realm.* import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import io.realm.kotlin.where import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.FutureTask class MainActivity : AppCompatActivity() { lateinit var uiThreadRealm: Realm override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Realm.init(this) // context, usually an Activity or Application val realmName: String = "My Project" val config = RealmConfiguration.Builder() .name(realmName) .build() uiThreadRealm = Realm.getInstance(config) addChangeListenerToRealm(uiThreadRealm) val task : FutureTask<String> = FutureTask(BackgroundQuickStart(), "test") val executorService: ExecutorService = Executors.newFixedThreadPool(2) executorService.execute(task) } fun addChangeListenerToRealm(realm : Realm) { // all tasks in the realm val tasks : RealmResults<Task> = realm.where<Task>().findAllAsync() tasks.addChangeListener(OrderedRealmCollectionChangeListener<RealmResults<Task>> { collection, changeSet -> // process deletions in reverse order if maintaining parallel data structures so indices don't change as you iterate val deletions = changeSet.deletionRanges for (i in deletions.indices.reversed()) { val range = deletions[i] Log.v("QUICKSTART", "Deleted range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } val insertions = changeSet.insertionRanges for (range in insertions) { Log.v("QUICKSTART", "Inserted range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } val modifications = changeSet.changeRanges for (range in modifications) { Log.v("QUICKSTART", "Updated range: ${range.startIndex} to ${range.startIndex + range.length - 1}") } }) } override fun onDestroy() { super.onDestroy() // the ui thread realm uses asynchronous transactions, so we can only safely close the realm // when the activity ends and we can safely assume that those transactions have completed uiThreadRealm.close() } class BackgroundQuickStart : Runnable { override fun run() { val realmName: String = "My Project" val config = RealmConfiguration.Builder().name(realmName).build() val backgroundThreadRealm : Realm = Realm.getInstance(config) val task : Task = Task() task.name = "New Task" backgroundThreadRealm.executeTransaction { transactionRealm -> transactionRealm.insert(task) } // all tasks in the realm val tasks : RealmResults<Task> = backgroundThreadRealm.where<Task>().findAll() // you can also filter a collection val tasksThatBeginWithN : List<Task> = tasks.where().beginsWith("name", "N").findAll() val openTasks : List<Task> = tasks.where().equalTo("status", TaskStatus.Open.name).findAll() val otherTask: Task = tasks[0]!! // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction { transactionRealm -> val innerOtherTask : Task = transactionRealm.where<Task>().equalTo("name", otherTask.name).findFirst()!! innerOtherTask.status = TaskStatus.Complete.name } val yetAnotherTask: Task = tasks.get(0)!! val yetAnotherTaskName: String = yetAnotherTask.name // all modifications to a realm must happen inside of a write block backgroundThreadRealm.executeTransaction { transactionRealm -> val innerYetAnotherTask : Task = transactionRealm.where<Task>().equalTo("name", yetAnotherTaskName).findFirst()!! innerYetAnotherTask.deleteFromRealm() } // because this background thread uses synchronous realm transactions, at this point all // transactions have completed and we can safely close the realm backgroundThreadRealm.close() } } } enum class TaskStatus(val displayName: String) { Open("Open"), InProgress("In Progress"), Complete("Complete"), } open class Task() : RealmObject() { var name: String = "task" var status: String = TaskStatus.Open.name var statusEnum: TaskStatus get() { // because status is actually a String and another client could assign an invalid value, // default the status to "Open" if the status is unreadable return try { TaskStatus.valueOf(status) } catch (e: IllegalArgumentException) { TaskStatus.Open } } set(value) { status = value.name } }
出力
上記のコードを実行すると、次のような出力が生成されます。
Successfully authenticated anonymously. Updated range: 0 to 1 Deleted range: 0 to 1 Successfully logged out.