Docs Menu
Docs Home
/ /
Atlas Device SDK
/

Java SDK에서 코틀린 SDK(Kotlin SDK)로 마이그레이션하기

이 페이지의 내용

  • 개요
  • Kotlin SDK 아키텍처
  • Realm 열기
  • Realm 객체 모델
  • 관계
  • 일대일
  • 일대다
  • 스키마 유형
  • 쓰기
  • 비동기
  • 동기화
  • 쿼리
  • 필터
  • 정렬, 구분, 제한
  • 삭제
  • 알림
  • 스레딩
  • 마이그레이션
  • 다음 단계는 무엇인가요?

참고

코틀린 SDK (Kotlin SDK)란 무엇인가요?

코틀린 SDK (Kotlin SDK)는 완전히 코틀린 (Kotlin) 프로그래밍 언어로 구축된 새로운 Realm 클라이언트 SDK입니다. 코틀린 SDK (Kotlin SDK)는 Java SDK와는 완전히 다른 코드베이스를 사용합니다. 코루틴 및 일시 중단 함수와 같은 코틀린 (Kotlin) 언어 기능을 활용하도록 특별히 설계되었습니다. 자바 SDK는 이러한 기능 중 일부와 코틀린 (Kotlin)으로 작성된 안드로이드 애플리케이션도 지원합니다. 하지만 코틀린 SDK (Kotlin SDK)는 Java SDK보다 관용적 코틀린 (Kotlin)에 가깝습니다.

Java SDK와 코틀린 SDK (Kotlin SDK)는 여러 면에서 다릅니다. 이 페이지에서는 SDK의 주요 차이점에 대한 개략적인 비교를 확인할 수 있습니다.

Java SDK는 기본 데이터가 변경될 때 자동으로 업데이트되는 라이브 객체, 쿼리 및 영역을 제공했습니다. 코틀린 SDK (Kotlin SDK)는 여전히 쓰기 트랜잭션(write transaction)에서 이 라이브 인터페이스를 제공하지만 그 외에는 영역 객체를 더 쉽게 사용할 수 있게 해주는 새로운 동결 아키텍처를 사용합니다. 다음은 Java SDK 아키텍처와 코틀린 SDK (Kotlin SDK) 아키텍처 간의 주요 차이점 중 일부입니다.

  • 기본적 동결: 이제 모든 객체가 동결됩니다. 라이브 객체와 달리 동결 객체는 데이터베이스 쓰기 후에 자동으로 업데이트되지 않습니다. 쓰기 트랜잭션(write transaction) 내에서 라이브 객체에 계속 액세스할 수 있지만 쓰기 트랜잭션(write transaction)에서 라이브 객체를 전달하면 객체가 고정됩니다.

  • 스레드 안전: 이제 모든 영역 인스턴스, 객체, 쿼리 결과 및 컬렉션을 스레드 간에 전송할 수 있습니다.

  • 싱글톤: 이제 각 영역 의 인스턴스 가 하나만 필요합니다. 개별 스레드에서 Realm을 열고 닫을 필요가 없습니다.

다음도 참조하세요.

Java SDK는 애플리케이션에 정의된 영역 객체 모델을 자동으로 감지하고 별도로 지정하지 않는 한 열린 영역의 스키마에서 해당 모델을 모두 사용합니다. 코틀린 SDK (Kotlin SDK)를 사용하려면 영역 스키마에서 사용할 영역 객체 모델을 수동으로 지정해야 합니다. 또한:

  • 코틀린 SDK (Kotlin SDK)는 애플리케이션에서 기본 영역을 설정하고 액세스하는 기능을 제공하지 않습니다. 이제 스레드 전체에 걸쳐 영역, 객체 및 결과를 공유할 수 있으므로 글로벌 싱글톤을 대신 사용할 수 있습니다.

  • Java SDK는 RealmConfiguration.Builder().build() 을(를) 사용하여 RealmConfiguration 인스턴스를 생성했습니다. 코틀린 SDK (Kotlin SDK)를 사용하는 경우 RealmConfiguration.create() 대신 컴패니언 메서드 RealmConfiguration 를 사용합니다.

  • Java SDK는 정적 Realm.getInstance() 메서드를 사용하여 지정된 구성으로 영역을 열었습니다. 코틀린 SDK (Kotlin SDK)에서는 대신 정적 Realm.open() 메서드를 사용하세요.

val config = RealmConfiguration.Builder()
.build()
var realm: Realm
realm = Realm.getInstance(config)
Log.v(
"EXAMPLE",
"Successfully opened a realm: "
+ realm.path
)
RealmConfiguration config =
new RealmConfiguration.Builder()
.build();
Realm realm;
realm = Realm.getInstance(config);
Log.v("EXAMPLE",
"Successfully opened a realm: "
+ realm.getPath());
val config = RealmConfiguration.create(
setOf(Frog::class, Sample::class))
val realm = Realm.open(config)
Log.v("Successfully opened realm:" +
"${realm.configuration.name}")

선택적으로 RealmConfiguration.Builder를 사용하여 설정을 더욱 맞춤 설정할 수 있습니다.

Kotlin SDK
val config = RealmConfiguration.Builder(
setOf(Frog::class, Sample::class))
.name(REALM_NAME)
.deleteRealmIfMigrationNeeded()
.directory(PATH)
.encryptionKey(KEY)
.build()
val realm = Realm.open(config)
Log.v("Successfully opened realm:" +
realm.configuration.name
)

다음도 참조하세요.

Java SDK에서는 두 가지 방법 중 하나로 Realm 객체 모델을 선언합니다.

  • 확장 RealmObject

  • 구현 RealmModel

코틀린 SDK (Kotlin SDK)는 대신 RealmObject 인터페이스의 기본 메서드를 사용합니다. 코틀린 SDK (Kotlin SDK)를 사용하여 RealmObject 에서 상속하여 Realm 객체 모델을 선언합니다. 주석은 무시된 필드, 기본 키 및 인덱스와 같은 특수 속성이 있는 필드에 대해 Java에서와 동일한 방식으로 작동합니다.

open class Sample : RealmObject() {
@PrimaryKey
var stringField = "Realm"
var byteField: Byte = 0xA
// no support for chars: no charField
var shortField: Short = 17
var intField = 42
@Index
var longField = 256L
var booleanField = true
var floatField = 3.14f
var doubleField = 1.19840122
var timestampField = Date()
}
public class Sample extends RealmObject {
@PrimaryKey
public String stringField = "Realm";
public Byte byteField = 0xA;
// no support for chars: no charField
public Short shortField = 17;
public Integer intField = 42;
@Index
public Long longField = 256L;
public Boolean booleanField = true;
public Float floatField = 3.14f;
public Double doubleField =
1.19840122;
public Date timestampField =
new Date();
}
class Sample : RealmObject {
@PrimaryKey
var stringField: String = "Realm"
var byteField: Byte = 0xA
var charField: Char = 'a'
var shortField: Short = 17
var intField: Int = 42
@Index
var longField: Long = 256L
var booleanField: Boolean = true
var floatField: Float = 3.14f
var doubleField: Double = 1.19840122
var timestampField: RealmInstant =
RealmInstant.from(
100,
1000)
var objectIdField: ObjectId = ObjectId()
}

다음도 참조하세요.

Java 및 코틀린 SDK (Kotlin SDK)는 모두 Realm 객체 필드를 통해 관계를 선언합니다:

open class Child : RealmObject() {
var frog: Frog? = null
}
public class Child
extends RealmObject {
public Frog frog = null;
}
class Child : RealmObject {
var frog: Frog? = null
}

Java SDK를 사용하면 RealmList 유형의 필드와 일대다 관계를 정의할 수 있습니다. 코틀린 SDK (Kotlin SDK)는 여전히 RealmList 유형의 필드를 사용하지만, realmListOf() 컴패니언 메서드를 사용하여 RealmList 인스턴스를 인스턴스화해야 합니다.

open class Kid : RealmObject() {
var frogs = RealmList<Frog>()
}
public class Kid
extends RealmObject {
public RealmList<Frog> frogs =
new RealmList<Frog>();
}
class Kid : RealmObject {
var frogs: RealmList<Frog> =
realmListOf()
}

Java SDK를 사용할 때는 @Required 주석을 사용하여 영역 객체 모델에서 프리미티브 목록을 null로 변환할 수 없도록 만들어야 했습니다. 코틀린 SDK (Kotlin SDK)는 기본적으로 프리미티브 목록을 null로 변환할 수 없도록 설정합니다. ? 연산자를 사용하여 프리미티브 목록을 null로 만들 수 있습니다.

open class CollegeStudent : RealmObject() {
@Required
var notes = RealmList<String>()
var nullableNotes = RealmList<String>()
}
public class CollegeStudent
extends RealmObject {
@Required
public RealmList<String> notes =
new RealmList<String>();
public RealmList<String> nullableNotes =
new RealmList<String>();
}
class Student : RealmObject {
var notes: RealmList<String> =
realmListOf()
var nullableNotes: RealmList<String?> =
realmListOf()
}

코틀린 SDK (Kotlin SDK)는 영역에 쓰는 메서드에 새로운 이름을 도입했습니다.

Java SDK를 사용하면 realm.executeTransactionAsync()이(가) 있는 영역에 비동기식으로 작성할 수 있습니다. 코틀린 SDK (Kotlin SDK)는 일시 중단 함수 realm.write()를 사용합니다. 그 대신

realm.executeTransactionAsync {
transactionRealm: Realm ->
val sample: Sample =
Sample()
sample.stringField = "Sven"
transactionRealm.copyToRealm(
sample
)
}
realm.executeTransactionAsync(
transactionRealm -> {
Sample sample = new Sample();
sample.stringField = "Sven";
transactionRealm.copyToRealm(sample);
});
realm.write {
// this: MutableRealm
val sample = Sample()
sample.stringField = "Sven"
this.copyToRealm(sample)
}

Java SDK를 사용하면 realm.executeTransaction() 을(를) 사용하여 영역에 동기적으로 쓸 수 있습니다. 코틀린 SDK (Kotlin SDK)는 realm.writeBlocking()을 사용합니다:

realm.executeTransaction {
transactionRealm: Realm ->
val sample: Sample =
Sample()
sample.stringField = "Sven"
transactionRealm.copyToRealm(
sample
)
}
realm.executeTransaction(
transactionRealm -> {
Sample sample = new Sample();
sample.stringField = "Sven";
transactionRealm.copyToRealm(sample);
});
realm.writeBlocking {
// this: MutableRealm
val sample = Sample()
sample.stringField = "Sven"
this.copyToRealm(sample)
}

Java SDK의 쿼리와 코틀린 SDK (Kotlin SDK)의 쿼리 간에는 몇 가지 차이점이 있습니다.

val samples =
realm.where(
Sample::class.java
).findAll()
val samplesThatBeginWithN =
realm.where(
Sample::class.java
)
.beginsWith(
"stringField",
"N"
).findAll()
RealmResults<Sample> samples =
realm
.where(Sample.class)
.findAll();
RealmResults<Sample> samplesThatBeginWithN =
realm
.where(Sample.class)
.beginsWith("stringField",
"N")
.findAll();
val samples: RealmResults<Sample> =
realm.query<Sample>().find()
val samplesThatBeginWithN:
RealmResults<Sample> =
realm.query<Sample>(
"stringField BEGINSWITH 'N'"
).find()
val aggregates =
realm.where(
Sample::class.java
)
.distinct("stringField")
.sort(
"stringField",
Sort.ASCENDING
)
.limit(2)
.findAll()
RealmResults<Sample> aggregates =
realm.where(Sample.class)
.distinct("stringField")
.sort("stringField",
Sort.ASCENDING)
.limit(2)
.findAll();
val aggregates: RealmResults<Sample> =
realm.query<Sample>()
.distinct(Sample::stringField.name)
.sort(Sample::stringField.name,
Sort.ASCENDING)
.limit(2)
.find()

두 SDK 모두 라이브 객체만 삭제할 수 있습니다. 코틀린 SDK (Kotlin SDK)는 mutableRealm.findLatest() 동결된 객체의 라이브 버전에 액세스합니다. 쓰기 트랜잭션(write transaction)에서는 findLatest() 을(를) 사용하지 않고 라이브 객체를 직접 쿼리하고 삭제할 수 있습니다.

val sample =
realm.where(
Sample::class.java
).findFirst()
// delete one object synchronously
realm.executeTransaction {
transactionRealm: Realm? ->
sample!!.deleteFromRealm()
}
// delete a query result asynchronously
realm.executeTransactionAsync {
backgroundRealm: Realm ->
backgroundRealm.where(
Sample::class.java
).findFirst()!!.deleteFromRealm()
}
Sample sample =
realm.where(Sample.class)
.findFirst();
// delete one object synchronously
realm.executeTransaction(
transactionRealm ->
sample.deleteFromRealm());
// delete a query result asynchronously
realm.executeTransactionAsync(
backgroundRealm ->
backgroundRealm
.where(Sample.class)
.findFirst()
.deleteFromRealm());
val sample: Sample? =
realm.query<Sample>()
.first().find()
// delete one object synchronously
realm.writeBlocking {
if (sample != null) {
findLatest(sample)
?.also { delete(it) }
}
}
// delete a query result asynchronously
GlobalScope.launch {
realm.write {
query<Sample>()
.first()
.find()
?.also { delete(it) }
}
}

컬렉션에 대한 변경 사항을 두 SDK 모두에서 구독할 수 있습니다. Java SDK를 사용하면 다음 인터페이스를 통해 영역결과가 변경될 때마다 알림을 받을 수 있습니다.

  • realmResults.addChangeListener()

  • 을(를) 통한 RxJava asFlowable()

  • 이(가) 포함된 코틀린(Kotlin) 확장 toFlow()

코틀린 SDK (Kotlin SDK)는 이러한 모든 옵션을 realmQuery.asFlow() 로 대체합니다. 결과 흐름이 있으면 collection 을 호출할 수 있습니다. 변경 사항을 구독합니다. 흐름에서 내보낸 UpdatedResults 유형의 객체는 결과 집합의 변경 사항을 나타냅니다.

realm.where(Sample::class.java)
.findAllAsync()
.addChangeListener {
samples: RealmResults<Sample>?,
changeSet: OrderedCollectionChangeSet ->
// log change description
Log.v(
"EXAMPLE",
("Results changed. " +
"change ranges: " +
Arrays.toString(
changeSet
.changeRanges
) +
", insertion ranges: " +
Arrays.toString(
changeSet
.insertionRanges
) +
", deletion ranges: " +
Arrays.toString(
changeSet
.deletionRanges
))
)
}
realm.where(Sample.class).findAllAsync()
.addChangeListener(
(samples, changeSet) -> {
// log change description
Log.v("EXAMPLE",
"Results changed. " +
"change ranges: " +
Arrays.toString(
changeSet
.getChangeRanges()) +
", insertion ranges: " +
Arrays.toString(
changeSet
.getInsertionRanges()) +
", deletion ranges: " +
Arrays.toString(
changeSet
.getDeletionRanges()));
});
// in a coroutine or a suspend function
realm.query<Sample>().asFlow().collect {
results: ResultsChange<Sample> ->
when (results) {
is InitialResults<Sample> -> {
// do nothing with the
// initial set of results
}
is UpdatedResults<Sample> -> {
// log change description
Log.v("Results changed. " +
"change ranges: " +
results.changeRanges +
", insertion ranges: " +
results.insertionRanges +
", deletion ranges: " +
results.deletionRanges
)
}
}
}

Java SDK를 사용하면 영역, Realm 객체 및 결과를 스레드 간에 전달할 수 없습니다. 코틀린 SDK (Kotlin SDK)는 기본적으로 이러한 객체를 고정하여 스레드로부터 안전하게 만듭니다. Java SDK에서 사용하는 라이브 객체와 달리 코틀린 SDK (Kotlin SDK)에 있는 동결 객체는 기본 데이터가 변경될 때 자동으로 업데이트되지 않습니다. 코틀린 SDK (Kotlin SDK)를 사용하는 경우 알림을 사용하여 업데이트를 구독해야 합니다.

realm = Realm.getInstance(config)
val sample =
realm.where(
Sample::class.java
).findFirst()
// save sample field in a
// separate variable
// for access on another thread
val sampleStringField =
sample!!.stringField
val executorService =
Executors.newFixedThreadPool(4)
executorService.execute {
// cannot pass a realm
// into another thread,
// so get a new instance
// for separate thread
val threadRealm =
Realm.getInstance(config)
// cannot access original
// sample on another
// thread, use
// sampleStringField instead
val threadSample =
threadRealm.where(
Sample::class.java
)
.equalTo(
"stringField",
sampleStringField
).findFirst()
Log.v(
"EXAMPLE",
"Separate thread sample: " +
threadSample
)
}
realm = Realm.getInstance(config);
Sample sample = realm
.where(Sample.class).findFirst();
// save sample field in a variable
// for access on another thread
String sampleStringField =
sample.stringField;
ExecutorService executorService =
Executors.newFixedThreadPool(4);
executorService.execute(() -> {
// cannot pass a realm
// into another thread,
// so get a new instance
// for separate thread
Realm threadRealm =
Realm.getInstance(config);
// cannot access original
// sample on another
// thread, use
// sampleStringField instead
Sample threadSample =
threadRealm
.where(Sample.class)
.equalTo("stringField",
sampleStringField)
.findFirst();
Log.v("EXAMPLE",
"Separate thread sample: "
+ threadSample);
});
val realm = Realm.open(config)
val sample: Sample? =
realm.query<Sample>()
.first()
.find()
launch(Dispatchers.Unconfined) {
// can access the realm opened on
// a different thread
realm.query<Sample>().find()
// can access realm object queried
// on a different thread
Log.v(sample!!.stringField)
}.join()

다음도 참조하세요.

Java SDK를 사용하면 마이그레이션을 수동으로 처리해야 했습니다. 코틀린 SDK (Kotlin SDK)는 마이그레이션을 자동화할 뿐만 아니라 마이그레이션 로직을 맞춤 조정할 수 있는 유사한 동적 영역 인터페이스에 대한 액세스도 제공합니다.

val config =
RealmConfiguration.Builder()
.migration { realm: DynamicRealm,
oldVersion: Long,
newVersion: Long ->
val schema: RealmSchema =
realm.schema
if (oldVersion == 0L) {
// perform schema migration
schema.get("Sample")
?.addField(
"new_field",
String::class.java
)
}
// migrate data
schema.get("Sample")
?.transform {
obj: DynamicRealmObject ->
obj.set(
"longField",
42L
)
}
}.build()
val realm: Realm =
Realm.getInstance(config)
Log.v(
"EXAMPLE",
"Successfully opened a realm: "
+ realm.path
)
RealmConfiguration config =
new RealmConfiguration.Builder()
.migration((realm,
oldVersion,
newVersion) -> {
RealmSchema schema =
realm.getSchema();
if (oldVersion == 0L) {
// perform schema migration
schema.get("Sample")
.addField("new_field",
String.class);
}
// migrate data
schema.get("Sample")
.transform(obj ->
obj.set("longField",
42L));
}).build();
Realm realm;
realm = Realm.getInstance(config);
Log.v("EXAMPLE",
"Successfully opened a realm: "
+ realm.getPath());
// A Realm migration that performs
// automatic schema migration
// and allows additional custom
// migration of data.
RealmConfiguration.Builder(
schema = setOf(Sample::class))
.migration(AutomaticSchemaMigration {
context:
AutomaticSchemaMigration.MigrationContext ->
val oldRealm:
DynamicRealm =
context.oldRealm
val newRealm:
DynamicMutableRealm =
context.newRealm
// dynamic realm gives access
// to realm data
// through a generic string
// based API
context.enumerate("Sample") {
oldObject:
DynamicRealmObject,
newObject:
DynamicMutableRealmObject? ->
newObject?.set("longField",
42L)
}
})
.build()
val realm = Realm.open(config)

이제 Java SDK와 코틀린 SDK (Kotlin SDK)의 차이점을 이해했으므로 나머지 코틀린 SDK (Kotlin SDK) 문서를 확인하세요.

돌아가기

SDK 원격 분석