Docs Menu
Docs Home
/ /
Atlas Device SDK

빠른 시작 - Java SDK

이 페이지의 내용

  • Realm 초기화
  • 객체 모델 정의
  • Realm 열기
  • 객체 만들기, 읽기, 업데이트 및 삭제
  • 변화를 주시하세요
  • 전체 예시
  • 출력

이 가이드에서는 Device Sync를 사용하지 않습니다.

이 가이드 는 장치 로컬 Realm 을 시작하는 데 도움이 될 수 있습니다. 애플리케이션 이 Atlas Device Sync, Realm Functions 또는 사용자 관리 와 같은 기능을 사용하여 네트워크를 통해 백엔드 앱과 통신해야 하는 경우 동기화를 통한 빠른 시작 가이드 를 따라야 합니다.

이 페이지에는 Realm을 앱에 빠르게 통합하기 위한 정보가 포함되어 있습니다. 시작하기 전에 다음 사항이 있는지 확인하세요.

  • Java SDK 설치

앱에서 Realm을 사용하려면 먼저 Realm 라이브러리를 초기화해야 합니다. 애플리케이션은 애플리케이션이 실행될 때마다 Realm을 한 번만 초기화해야 합니다.

Realm 라이브러리를 초기화하려면 Realm.init() 정적 함수에 Android context 를 제공합니다. 동작의 차이 없이 초기화를 위해 활동, 프래그먼트 또는 애플리케이션 context 을(를) 제공할 수 있습니다. 애플리케이션 onCreate() 서브클래스 의 메서드에서 Realm 라이브러리를 초기화할 수 있습니다. 애플리케이션 이 실행될 때마다 Realm 을 한 번만 초기화하도록 합니다.

Realm.init(this); // context, usually an Activity or Application
Realm.init(this) // context, usually an Activity or Application

Android 매니페스트에 애플리케이션 서브클래스 등록

자체 Application 하위 클래스를 생성하는 경우 사용자 지정 애플리케이션 로직을 실행하려면 이를 애플리케이션의 AndroidManifest.xml 에 추가해야 합니다. 매니페스트 애플리케이션 정의의 android.name 속성을 설정하여 사용자가 애플리케이션을 실행할 때 Android가 다른 클래스보다 먼저 Application 하위 클래스를 인스턴스화하도록 합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mongodb.example">
<application
android:name=".MyApplicationSubclass"
...
/>
</manifest>

애플리케이션의 데이터 모델 은 Realm 내에 저장된 데이터의 구조를 정의합니다. Realm 객체 모델을 사용하여 애플리케이션 코드의 코틀린 (Kotlin) 또는 Java 클래스를 통해 애플리케이션의 데이터 모델 을 정의할 수 있습니다.

애플리케이션의 데이터 모델 을 정의하려면 애플리케이션 코드에 다음 클래스 정의를 추가하세요.

Task.java
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;
public class Task extends RealmObject {
@PrimaryKey private String name;
@Required 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() {}
}
TaskStatus.java
public enum TaskStatus {
Open("Open"),
InProgress("In Progress"),
Complete("Complete");
String displayName;
TaskStatus(String displayName) {
this.displayName = displayName;
}
}
Task.kt
enum class TaskStatus(val displayName: String) {
Open("Open"),
InProgress("In Progress"),
Complete("Complete"),
}
open class Task() : RealmObject() {
@PrimaryKey
var name: String = "task"
@Required
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 }
}

RealmConfiguration 를 사용하여 영역 의 이름이나 위치 , UI 스레드에서 영역 에 대한 동기 읽기 또는 쓰기 허용 여부 등 열려는 영역 의 세부 사항을 제어할 수 있습니다.

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)

영역 을 연 후에는 쓰기 트랜잭션( 쓰기 트랜잭션 (write transaction) ) 차단 에서 해당 영역 내의 객체 를 수정할 수 있습니다.

중요

UI 스레드의 동기식 읽기 및 쓰기

기본적으로 비동기 트랜잭션을 사용하여 애플리케이션의 UI 스레드에서 영역에 읽기 또는 쓰기만 가능합니다. 즉, 동기 메서드의 사용을 명시적으로 허용하지 않는 한 Android 애플리케이션의 기본 스레드에서 이름이 Async(이)라는 단어로 끝나는 Realm 메서드만 사용할 수 있습니다.

이러한 제한은 애플리케이션 사용자를 위해 존재합니다. 즉, UI 스레드에서 읽기 및 쓰기 작업을 수행하면 UI 상호 작용이 응답하지 않거나 느려질 수 있으므로 일반적으로 이러한 작업을 비동기적으로 처리하거나 배경 스레드에서 처리하는 것이 가장 좋습니다. 하지만 애플리케이션이 UI 스레드에서 동기 영역 읽기 또는 쓰기를 사용해야 하는 경우 다음 SyncConfiguration 옵션을 사용하여 동기 메서드 사용을 명시적으로 허용할 수 있습니다.

SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION)
.allowQueriesOnUiThread(true)
.allowWritesOnUiThread(true)
.build();
Realm.getInstanceAsync(config, new Realm.Callback() {
@Override
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)
}

영역 에 있는 모든 항목의 라이브 컬렉션 을 조회 할 수 있습니다.

// 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()

작업을 수정하려면 쓰기 트랜잭션(write transaction) 차단에서 해당 속성을 업데이트합니다.

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
}

마지막으로 쓰기 트랜잭션( 쓰기 트랜잭션 (write transaction) ) 차단 에서 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 를 첨부하여 영역, 컬렉션 또는 객체 의 변경 사항 을 확인할 수 있습니다.

// all Tasks in the realm
RealmResults<Task> Tasks = uiThreadRealm.where(Task.class).findAllAsync();
Tasks.addChangeListener(new OrderedRealmCollectionChangeListener<RealmResults<Task>>() {
@Override
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를 사용하는 경우 TaskTaskStatus 에 대한 import 문을 업데이트 합니다.

Task.java
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;
public class Task extends RealmObject {
@PrimaryKey private String name;
@Required 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() {}
}
TaskStatus.java
public enum TaskStatus {
Open("Open"),
InProgress("In Progress"),
Complete("Complete");
String displayName;
TaskStatus(String displayName) {
this.displayName = displayName;
}
}
MainActivity.java
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;
@Override
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>>() {
@Override
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)); }
}
});
}
@Override
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 {
@Override
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();
}
}
}
MainActivity.kt
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() {
@PrimaryKey
var name: String = "task"
@Required
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.

다음

Atlas Device SDK Docs에 오신 것을 환영합니다