realm 코딩카페 - 이종찬

97
0 Realm for Android Made by 이종찬

Upload: lee-jong-chan

Post on 06-Jan-2017

422 views

Category:

Technology


0 download

TRANSCRIPT

0

Realmfor Android

Made by 이종찬

1

01Realm?

2

모바일에 최적화된 데이터베이스

01 Realm?Realm이란 무엇인지 알아보자.

3

01 Realm?Realm을 지원하는 언어는 어떠한 것들이 있는지 알아보자.

지원하는 언어

4

빠른 쿼리와 검색빠르고 효율적입니다.

다양한 추가기능마이그레이션, 그래프 쿼리 등의 지원

쉬운 저장Object를 상속하면 된다.1

2

3

01 Realm?Realm의 장점을 알아보자.

장점

5

현재(1.0.1)는 Android의 java환경만 지원12 Android Studio 버전 1.5.1 이상

최신 버전의 Android SDK345 API 9 (Android 2.3 진저브레드) 이상 지원

JDK 버전 7이상

시작하기-요구사항01 Realm?Android에서 Realm을 사용하기 위한 요구사항을 알아보자.

6

V1.0.0 이상에서 Elipse는 지원되지 않는다.Android Studio로 이전하는 것을 제안한다.

ProGuard 설정이 포함되어 있다.ProGuard 규칙을 추가할 필요가 없다.

Realm은 gradle 플러그인으로 설치된다.Maven과 Ant 빌드 시스템은 지원되지 않는다.

시작하기-설치하기01 Realm?Android Studio에서 Realm을 설치하는 법을 알아보자.

7

1 프로젝트 수준 build.gradle 파일에클래스 패스 의존성을 추가한다.

버전은 최신 버전을 적어주면 된다.

시작하기-설치하기01 Realm?Android Studio에서 Realm을 설치하는 법을 알아보자.

buildscript {repositories {

jcenter()}dependencies {

classpath "io.realm:realm-gradle-plugin:1.0.1"}

}

8

2 App 수준 build.gradle 파일에realm-android 플러그인을 적용시킨다.

시작하기-설치하기01 Realm?Android Studio에서 Realm을 설치하는 법을 알아보자.

dependencies {apply plugin: 'realm-android'

}

9

프로젝트창이다음과같을때(realm 문서에있는형태)

App 수준

Project 수준

시작하기-설치하기01 Realm?Android Studio에서 Realm을 설치하는 법을 알아보자.

10

프로젝트창이다음과같을때(realm 문서에있는형태)

App 수준Project 수준

보이는화면은여기를눌러서바꿀수있다.

시작하기-설치하기01 Realm?Android Studio에서 Realm을 설치하는 법을 알아보자.

11

https://github.com/realm/realm-java/tree/master/examples

introExample – 현재 api 사용에 대한 간단한 예제

glridViewExample – GridView을 위한 뒷단의 스토어로 realm을 사용하는 예제

threadExample – 다중 쓰레드 환경에서의 예제

adapterExample - RealmResults를 편리하게 리스트에 연결하는 예제

jsonExample – json 기능을 사용하는 예제

encryptionExample – 암호화를 어떻게 하는지 보여주는 예제

RxJavaExample - RxJava와 어떻게 동작하는지 보여주는 예제

unitTestExample – 유닛 테스트에 대한 예제

그 외에도 kotlinExample, migrationExample, moduleExample,

newsreaderExample 예제가 있다.

예제01 Realm?Realm 예제의 종류에 대해서 알아보자.

12

02Realm 객체

13

02 Realm 객체Realm을 설정하기 위해 사용하는 객체에 대해서 알아보자.

1. Realm 데이터베이스 파일의 위치, 이름, 스키마버전 등을설정하기 위해 사용하는 객체

2. RealmConfiguration 객체에 realm 에 대한 설정을 먼저 한 후Realm 객체를 생성한다.

3. RealmConfiguration 객체는 빌더 패턴에 의해 생성된다.4. 여러 개의 RealmConfiguration 객체를 쓰는 것도 가능하다.

1 RealmConfiguration 생성하기

RealmConfiguration config = new RealmConfiguration.Builder(context).build();// 최소한의 설정만 할 때 사용. 파일의 이름은 default.realm 으로 들어간다.

RealmConfiguration config = new RealmConfiguration.Builder(context).name("myrealm.realm").encryptionKey(getKey()).schemaVersion(42).modules(new MySchemaModule()).migration(new MyMigration()).build();

// Realm 파일은 Context.getFilesDir()에 위치하면 이름은 "myrealm.realm"입니다.

RealmConfiguration

14

빌더 패턴 (builder pattern)

1. 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서서로 다른 표현 결과를 만들 수 있게 하는 패턴이다.

2. 합성할 객체들의 표현이 서로 다르더라도 생성 절차에서이를 지원해야할 때 사용한다.

3. 조건에 따라서 각각 다른 빌더 클래스를 이용, 다른 연산을 수행하고객체를 생성하는 부분과 세부 알고리즘을 분리하는 패턴이다.

Realm에 적용된 이유를 알아보자. ( * 주의 : 단순 제 생각 입니다. * )

RealmConfiguration을 통해 Realm을 설정할 때 사용자 마다 다양한 설정값을줄 수 있다. (이름만 주거나, 스키마버전만 주거나 등등)

이 때 각각에 대한 설정을 좀더 쉽게 구성하게 해주는 패턴이빌더 패턴이기에 Realm에서는 RealmConfiguration의 생성을Builder 패턴으로 했을거라고 판단된다.

15

2 Realm 인스턴스 얻기

RealmConfiguration config = new RealmConfiguration.Builder(context).build();// 최소한의 설정만 할 때 사용. 파일의 이름은 default.realm 으로 들어간다.

RealmConfiguration config = new RealmConfiguration.Builder(context).name("myrealm.realm").encryptionKey(getKey()).schemaVersion(42).modules(new MySchemaModule()).migration(new MyMigration()).build();

// Realm 파일은 Context.getFilesDir()에 위치하면 이름은 "myrealm.realm"입니다.

Realm realm = Realm.getInstance(config); // 설정을 사용합니다.

1. 생성했던 RealmConfiguration 객체를 사용하여 Realm인스턴스를 얻는다.2. Realm인스턴스는 싱글톤 패턴으로 생성된다. 그렇기 때문에매 스레드마다 정적 생성자는 동일한 인스턴스를 반환한다.

02 Realm 객체Realm을 설정하기 위해 사용하는 객체에 대해서 알아보자.

Realm 인스턴스

16

싱글톤 패턴 (singleton pattern)

1. 객체가 단 하나면 충분하다고 판단 될 때 사용하는 패턴이다.2. 자바의 static 키워드를 사용하며 메모리 관리면에서 효율적인 패턴이다.

public class Singleton {private static Singleton singleton = new Singleton();

private Singleton() { } //private로 선언이 되어있기 때문에 사용할 수 없다.

public static Singleton getInstance(){return singleton;

} //getInstance를 사용해서만 객체를 얻어올 수 있다.}

Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println( s1 == s2 ); //true가 반환된다.

3. 생성자는 private로 선언하여 사용 할 수 없도록 한다.4. 객체의 생성은 한 번만 하고 같은 객체만을 반환하기 때문에객체는 항상 하나만 생성되어 있다.

17

싱글톤 패턴 (singleton pattern)

Realm에 적용된 이유를 알아보자. ( * 주의 : 단순 제 생각 입니다. * )

Thread 1A Realm 객체1

Thread 2A Realm 객체2

쓰기 중

쓰기 불가능

1. 2개의 쓰레드에 동일한 realm A에 대한 객체가 2개가 각각 존재한다고 하자.2. Thread1 에서 쓰기를 작업 중이면 Transaction에 의해 Thread2는

쓰기 작업을 할 수가 없다.3. Thread1 의 쓰기 작업이 끝났을 때 Thread2가 쓰기 작업을 할 수 있다. Thread1과 Thread2는 같은 Realm을 사용하기 때문에 한 번에 하나씩만쓰기 작업이 가능하다. 객체를 두 개 가지고 있는 것은 메모리 낭비이다.

메인 메모리 디스크

A Realm

18

싱글톤 패턴 (singleton pattern)

Realm에 적용된 이유를 알아보자. ( * 주의 : 단순 제 생각 입니다. * )

Thread 1

Thread 2

쓰기 중

쓰기 불가능

1. 메인 메모리 상에 singleton 패턴을 이용하여 Realm을 객체화 시켜둔다.2. 각 쓰레드에서는 A Realm에 대한 객체를 생성하지 않고 singleton에서

생성한 객체를 참조만 하고 있는다.3. 쓰기는 Transaction에 의해 하나 씩만 가능하므로 문제가 생기지 않는다. 메모리 관리면에서 훨씬 효율적이다.

메인 메모리

디스크

A Realm

A Realm 객체(singleton)

19

3 여러 개의 RealmConfiguration 쓰기

RealmConfiguration myConfig = new RealmConfiguration.Builder(context).name("myrealm.realm").schemaVersion(2).setModules(new MyCustomSchema()).build();

RealmConfiguration otherConfig = new RealmConfiguration.Builder(context).name("otherrealm.realm").schemaVersion(5).setModules(new MyOtherSchema()).build();

Realm myRealm = Realm.getInstance(myConfig);Realm otherRealm = Realm.getInstance(otherConfig);

1. 여러 개의 Realm파일을 만들고 싶을 때는 여러 개의 Configuration을사용하면 된다.

2. 이런 방법에서는 각 설정값을 Realm마다 독립적으로 제어할 수 있다.

02 Realm 객체Realm을 설정하기 위해 사용하는 객체에 대해서 알아보자.

RealmConfiguration

20

4 DefaultConfiguration으로 저장

public class MyApplication extends Application {@Overridepublic void onCreate() {

super.onCreate();// Context.getFilesDir()에 "default.realm"란 이름으로 Realm 파일이 위치한다RealmConfiguration config = new RealmConfiguration.Builder(this).build();Realm.setDefaultConfiguration(config);

}}public class MyActivity extends Activity {

@Overrideprotected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);Realm realm = Realm.getDefaultInstance();// ... 무엇을 합니다 ... realm.close();

}}

1. 커스텀 Application 클래스에 기본 설정을 넣으면다른 클래스에서 사용이 가능하다.

02 Realm 객체Realm을 설정하기 위해 사용하는 객체에 대해서 알아보자.

DefaultConfiguration

21

RealmConfiguration myConfig = new RealmConfiguration.Builder(context).name("myrealm.realm").build();

Realm myRealm = Realm.getInstance(myConfig);

1. 디스크에 저장되는 가장 기본적인 데이터베이스2. RealmConfiguration을 통해 Realm을 설정한 후getInstance등의 메소드를 통해 Realm 객체를 얻어온다.

02 Realm 객체사용할 수 있는 Realm의 종류를 알아보자.

Realm의 종류

1 기본 Realm

API(Realm.class) Public static Realm getDefaultInstance();(Realm.class) Public static Realm getInstance(RealmConfiguration configuration);// 모든 종류의 Realm 객체는 위의 메소드를 통해 얻는다.

22

1. 디스크에 저장하지 않는 인 메모리 Realm이 생성할 수 있다.2. 메모리가 부족하면 디스크를 이용하기는 한다.3. 모든 파일들은 메모리 상에서 생성되고 Realm이 닫히면 삭제된다.4. 디스크에 있는 Realm고 같은 이름의 인 메모리 Realm은 허용되지 않는다.5. 인 메모리 Realm 인스턴스는 어떤 레퍼런스도 가리키지 않을 때

Realm의 모든 데이터를 해제한다.

02 Realm 객체사용할 수 있는 Realm의 종류를 알아보자.

Realm의 종류

2 Inmemory Realm

RealmConfiguration myConfig = new RealmConfiguration.Builder(context).name("myrealm.realm").inMemory().build();

Realm myRealm = Realm.getInstance(myConfig);

경우에 따라 Serialize나 Parcelable보다 속도가 빠르기 때문에사용하는 것 같다. (* 주의 : 단순 제 생각 입니다. * )

23

1. Realm을 사용할 때 모델 클래스는 RealmObject의 서브클래스로 정의하여사용한다. 이때 형 안정성에 많은 이점이 있지만 어떤 경우에는 컴파일시점에서 사용이 가능하지 않을 수 있다. 이때 Dynamic Realm을 사용한다.

2. Dynamic Realm은 DynamicRealmObject라는 클래스로 사용하며 모든 필드에대한 접근을 클래스 대신 문자열을 통해 접근한다.

3. Dynamic Realm은 스키마, 마이그레이션, 스키마 버전은 무시한다.4. Dynamic Realm은 안정성과 성능을 포기하고 유연성을 선택하였다.때문에 정말로 유연성이 필요할 때만 사용하는 것을 권장한다.

3 Dynamic Realm

02 Realm 객체사용할 수 있는 Realm의 종류를 알아보자.

Realm의 종류

24

RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();DynamicRealm realm = DynamicRealm.getInstance(realmConfig);// DynamicRealm에서 모든 객체들은 DynamicRealmObjects입니다DynamicRealmObject person = realm.createObject("Person");

// 모든 필드는 문자열로 접근가능합니다.String name = person.getString("name");int age = person.getInt("age");

// 하부의 스키마는 존재하기에 존재하지 않는 필드에 예외를 발생시킵니다person.getString("I don't exist");

// 질의는 여전히 평범하게 동작합니다RealmResults<DynamicRealmObject> persons = realm.where("Person")

.equalTo("name", "John").findAll();

3 Dynamic Realm

02 Realm 객체사용할 수 있는 Realm의 종류를 알아보자.

Realm의 종류

25

사용을 완료한 Realm 객체를 어떻게 처리하는 방법을 알아보자.Realm 객체 닫기

1. Realm은 네이티브 메모리 해제와 파일 서술자를 다루기 위해 Closeable을구현한다. 때문에 Realm을 사용한 후 Realm 객체를 닫는 것은 중요하다.

2. Realm 인스턴스는 레퍼런스 카운팅이 된다. 즉 하나의 쓰레드에서getInstance()를 두 번 호출하면 사용이 끝난 후 close()도 두 번 호출해야 한다.

Closeable – java interface1. 자바에서 파일을 다룰 때 사용하는 것으로 판단된다. 파일을 사용하는 객체는claseable이 구현되어 있어 사용을 다 한 후에는 close()를 호출해야 되는 것 같다.

2. Try – catch – finally 문에서 실행되며 자바 7이전 버전에서는 수동으로close()를 호출해 줘야 했다.

3. 자바 7 버전 부터는 try-with-resources 문이 추가되어 자동으로 수동으로close()를 호출하는 작업을 해줄 필요가 없어졌다.

02 Realm 객체

26

사용을 완료한 Realm 객체를 어떻게 처리하는 방법을 알아보자.Realm 객체 닫기

1 UI 쓰레드에서 닫기

1. UI 쓰레드에서는 onDestory()에서 realm.close()를 호출하는 것이 간단하다.

2 Try-with-resource 사용하기

// minSdkVersion >= 19 이상이며 Java >= 7 인 앱에서만 가능하다.try (Realm realm = Realm.getDefaultInstance()) {

// 수동으로 Realm 인스턴스를 닫을 필요가 없습니다}

02 Realm 객체

27

사용을 완료한 Realm 객체를 어떻게 처리하는 방법을 알아보자.Realm 객체 닫기

Looper 쓰레드에서 닫기

public class MyThread extends Thread {private Realm realm;@Overridepublic void run() {

Looper.prepare();try {

realm = Realm.getDefaultInstance();// ... Realm 인스턴스를 사용합니다 ...Lopper.loop();

} finally {if (realm != null)

realm.close();}

}}

3

02 Realm 객체

28

사용을 완료한 Realm 객체를 어떻게 처리하는 방법을 알아보자.Realm 객체 닫기

4 AsyncTask에서 닫기

protected Void doInBackground(Void... params) {Realm realm = null;try {

realm = Realm.getDefaultInstance();// ... Realm 인스턴스를 사용합니다 ...

} finally {if (realm != null)

realm.close();}return null;

}

02 Realm 객체

29

사용을 완료한 Realm 객체를 어떻게 처리하는 방법을 알아보자.Realm 객체 닫기

5 짧게 사용하고 닫기(Thread나 Runnable)

// Realm 인스턴스와 비 Looper 스레드를 실행합니다.Thread thread = new Thread(new Runnable() {

@Overridepublic void run() {

Realm realm = null;try {

realm = Realm.getDefaultInstance();// ... Realm 인스턴스를 사용합니다 ...

} finally {if (realm != null)

realm.close();}

}});

thread.start();

02 Realm 객체

30

Realm 파일을 찾는 법을 알아보자.Realm 파일 찾기

1 Realm 브라우저 사용

1. 현재 Realm 브라우저는 맥OS 에서만 지원되며 다른 운영체제에서는지원되지 않고 있다.

2. Realm 브라우저를 사용하여 Realm 데이터베이스를 읽고 수정이 가능하다.3. 하지만 현재 브라우저는 디바이스에 직접적인 접근을 하지 못한다.4. 때문에 디바이스에서 데이터베이스를 복사를 하여 접근해야 한다.

02 Realm 객체

31

03모델

32

박스형Boolean, Byte, Short, Integer, Long, Float, Double-> 박스형과 RealmObject형 필드만 null 값을 넣을 수 있다.

서브클래스 및 리스트형RealmObject의 서브클래스, RealmList <? Extends RealmObject>

기본형boolean, short, int, long, float, double, String, Date, byte[]-> short, int, long 은 Realm 내에서 모두 long으로 대응된다.

1

2

3

Realm에서 지원하는 필드 타입을 알아보자.Field03 모델(Model)

33

Realm에서 지원하는 필드 타입을 알아보자.Field03 모델(Model)

public class Dog extends RealmObject {public String name;public int age;

}

public RealmList<Dog> dogs;

34

Realm에서 사용되는 어노테이션(annotation)을 알아보자.

1 @Required

1 null 값을 허용하지 않기 위해 사용한다.2 박스형만 지정할 수 있다.3 기본형과 RealmList는 암묵적으로 Required로 취급한다.4 RealmObject는 항상 널이 가능

2 @Ignore

1 필드가 디스크에 저장되지 않도록 하는 기능을 한다.2 사용자의 입력이 모델의 필드보다 많을 때, 쓰지 않을 데이터 필드를 다룰 때 사용한다.

Annotation03 모델(Model)

35

3 @Index

1 해당 필드에 검색 색인을 추가한다.2 질의 처리를 빠르게 할 수 있다.3 삽입 처리가 느리고 데이터의 파일을 크게 만든다.4 읽기에 최적화를 하는 경우에만 추가하는 것을 추천한다.5 String, byte, short, int, long, Boolean, Date에 가능하다.

Realm에서 사용되는 어노테이션(annotation)을 알아보자.Annotation03 모델(Model)

36

4 @PrimaryKey

1 문자열(String)이나 정수(byte, short, int, long)이나 이에대응하는 박스형(Byte, Short, Integer, Long)에 가능하다.

2 여러 필드를 PrimaryKey로 설정하는 것은 불가능하다.3 @PrimaryKey는 암묵적으로 @Index를 설정한다.4 PrimaryKey를 사용하면 Querying의 속도는 향상될 수 있다.5 객체를 생성하고 수정할 때 속도하락이 있을 수 있다.6 String, byte, short, int, long, Boolean, Date 에 가능하다.

Realm에서 사용되는 어노테이션(annotation)을 알아보자.Annotation03 모델(Model)

37

1 일반적으로 사용하기RealmObject의 사용방법을 알아보자.

Object03 모델(Model)

public class Dog extends RealmObject {private String name;

public void setName(String name) { this.name = name; }public String getName() { return name; }

}

realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {

Dog dog = realm.createObject(Dog.class);dog.setName("Fido");

}});

38

2 POJO(Plain Old Java Object)처럼 사용하기

요구사항에 맞춰서 getter와 setter에 로직을 추가할 수도 있다.

RealmObject의 사용방법을 알아보자.Object03 모델(Model)

realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {

Dog dog = realm.createObject(Dog.class);dog.name = “Fido”;

}});

public class Dog extends RealmObject {public String name;

}

39

POJO(Plain Old Java Object)란?

POJO : 프레임워크 등에 종속된 ‘무거운’ 객체를만들게 된 것에(EJB에) 반발해서 사용하게 된 용어

POJO의 필수요소1. light-weight(possibly) : 가볍게2. flexible : 유연성3. simple : 간단 명료4. supported by separate optional components

such as hibernate or spring

POJO가 아닌 대표적인 객체public HelloSevlet extends HttpServlet{...}-> 자바 서블릿 코드를 작성할 때는 반드시 HttpServlet을 상속받아야한다.-> 서플릿 프로그래밍을 한다는 이유로 상속이라는 핵심 기능을 빼앗긴 것

-> 개발자가 직접 상속을 할 수 있는 기회가 없어진 것이다.-> HttpServlet 을 상속 받았기 때문에 이 코드를 이해해야 하며어떤 기능이 있는지 어떻게 재사용해야 할지 판단하기도 어렵다.

40

현재 Realm에 어떠한 제약사항이 있는지 알아보자.제약사항

RealmObject 외의 상속을 허용하지 않는다.기본 생성자는 재정의 하지 말아야 한다.-> 기본 생성자에서 Realm 인스턴스가 주어져 있다고 가정하는메소드를 호출하기 때문이다.

-> RealmModel 인터페이스를 추가하는 방식으로 해결 할 수도 있다.

final, transient, volatile 지원하지 않는다.Realm에 의해 관리되는 객체와 비관리 객체 간의불일치를 막기 위해서입니다.

1

2

03 모델(Model)

41

04관계

42

Realm에서 관계는 어떻게 정의하는지 알아보자.

1 다 대 일

각 Author은 0혹은 1개의 Book을 갖는다.하지만 책에는 공동 저자 라는 것이 있다.즉, 여러 Author가 하나의 Book을 사용할 수 있다.이러한 관계가 다-대-일 이다.

author1

author2

author3

author4

book1

book2

다 대 일04 관계(Relationships)

public class Book extends RealmObject {private String title;// 다른 필드 및 getter, setter

}

public class Author extends RealmObject {private Book book;// 다른 필드 및 getter, setter

}

43

2 다 대 다

Author는 여러 권의 Book을 집필 했을 수 있다.이때 또한 공동 저자가 적용 될 수 있다.다-대-다 관계이다.RealmList를 이용하면 다-대-다 관계를 설정할 수 있다.

author1

author2

author3

author4

book1

book2

book3

Realm에서 관계는 어떻게 정의하는지 알아보자.다 대 다04 관계(Relationships)

public class Book extends RealmObject {private String title;// 다른 필드 및 getter, setter

}

public class Author extends RealmObject {private RealmList<Book> books;// 다른 필드 및 getter, setter

}

44

2 다 대 다RealmList는 자바의 List와 비슷한 행동을 한다.RealmList안에 객체를 추가하기 위해서는 RealmList.add()를 사용하면 된다.

realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {

Author author = realm. createObject(Author.class);

Book book = realm.createObject(Book.class);Book.settitle(“realm”);

author.books.add(book);}

});

Realm에서 관계는 어떻게 정의하는지 알아보자.다 대 다04 관계(Relationships)

45

RealmList의 사용

RealmList를 사용하여 재귀적인 관계도 설정 가능하다.

RealmList 필드에 null 값을 설정하면 리스트가 초기화된다.이것은 null로 바꾸는 것이 아닌 길이가 0인 리스트로 만드는 것이다.때문에 RealmList의 getter는 null을 절대 반환하지 않는다.길이가 0인 리스트를 반환한다.

public class Person extends RealmObject {private RealmList<Person> friends;// 다른 필드 및 getter, setter

}

46

05Transaction

47

1 Transaction이란?

1 데이터 베이스에서 읽거나 쓰기 위해 실행하는 여러 개의쿼리(질의)를 끊기지 않고 전부 수행하기 위한 것.-> 완전성(integrity)를 보장

2 Atomicity(원자성), Consistency(일관성), Isolation(고립성), Durability(영구성)을 보장한다.

Realm은 MVCC 아키텍처를 사용하기 때문에 쓰기 트랜잭션 실행되도읽기는 막히지 않는다.

-> 읽기는 언제든지 객체를 접근 할 수 있다.-> 추가, 수정, 삭제는 트랜잭션 안에서 해야한다.

Realm을 사용하기 전 Transaction에 대해서 간단히 알아보자.

05 Transaction

48

MVCC

다중 버전 동시성 제어(multiversion concurrency control)

A가 읽기에 대한 처리를 트랜잭션을 통해 수행하면 동일 데이터를다른 사람 B는 A가 끝날 때까지 접근을 할 수 없었다.

하지만 MVCC는 A가 트랜잭션을 할 때 동일한 데이터를 복사해 두어B도 동시에 접근을 가능하게 만들었다.

쉽게 말해서 [동시에 여러명이 접근이 가능하게 했다] 라는 것이다.

49

Realm에서 Transaction을 관리하는 법을 알아보자.

Transaction관리하기

1 수동으로 관리하기

// Realm 인스턴스를 얻습니다Realm realm = Realm.getDefaultInstance();

realm.beginTransaction();// 객체를 여기에서 추가하거나 갱신합니다

realm.commitTransaction();// commit이 호출되면 모든 작업이 정상적으로 완료한 것입니다.

realm.cancelTransaction();// 오류가 났을 때는 cancel을 호출하여 모든 작업을 취소할 수 있습니다.

05 Transaction

50

2 자동으로 관리하기

// Realm 인스턴스를 얻습니다Realm realm = Realm.getDefaultInstance();

realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {

User user = realm.createObject(User.class);user.setName("John");user.setEmail("[email protected]");

}});

Transaction 블록을 사용하여 간편하게 Transaction을 관리할 수 있다.

Realm에서 Transaction을 관리하는 법을 알아보자.

Transaction관리하기

05 Transaction

51

3 비동기 트랜잭션(Async)

realm.executeTransactionAsync(new Realm.Transaction() {@Overridepublic void execute(Realm bgRealm) {

// 수행할 내용.}

}, new Realm.Transaction.OnSuccess() {@Overridepublic void onSuccess() {

// 트랜잭션이 성공하면 호출되는 콜백 함수.}

}, new Realm.Transaction.OnError() {@Overridepublic void onError(Throwable error) {// 트랜잭션이 실패하면 호출되는 콜백 함수}

});

Realm에서 Transaction을 관리하는 법을 알아보자.

Transaction관리하기

05 Transaction

52

동기 & 비동기

동기 (Synchronous: 동시에 일어나는)- 요청과 그 결과가 동시에 일어난다는 약속- 장점 : 설계가 간단하고 직관적이다.- 단점 : 결과가 주어질 때까지 아무것도 못하고 대기해야 한다.

비동기 (Asynchronous: 동시에 일어나지 않는)- 요청과 그 결과가 동시에 일어나지 않을 것이라는 약속이다. -> 요청한 그 자리에서 바로 결과가 주어지는 것이 아니라,

이따가 준다고 약속하는 것이다.- 장점 : 결과가 주어지지 않아도 그 시간 동안 다른 작업을 할 수 있다.- 단점 : 설계가 복잡하다.

53

3 비동기 트랜잭션(Async)

APIPublic RealmAsyncTask executeTransactionAsync(Realm.Transaction transaction);Public RealmAsyncTask executeTransactionAsync(Realm.Transaction transaction,

Realm.Transaction.OnSuccess onSuccsess);Public RealmAsyncTask executeTransactionAsync(Realm.Transaction transaction,

Realm.Transaction.OnError onError);Public RealmAsyncTask executeTransactionAsync(Realm.Transaction transaction,

Realm.Transaction.OnSuccess onSuccsess,Realm.Transaction.OnError onError);

백그라운드 쓰레드에서 쓰기 작업을 하는 중인데 UI 쓰레드가 쓰기 작업을하려고 하면 ANR에러가 발생할 수 있다.-> 때문에 비동기 트랜잭션을 사용한다.

OnSuccess와 OnError 콜백은 선택 사항으로 사용하면 된다.콜백은 Looper에 의해 제어되고 Looper 스레드에서만 허용된다.

Realm에서 Transaction을 관리하는 법을 알아보자.

Transaction관리하기

05 Transaction

54

3 비동기 트랜잭션(Async)

비동기 트랜잭션은 RealmAsyncTask 객체로서 저장할 수 있다.

RealmAsyncTask transaction = realm.executeTransactionAsync(new Realm.Transaction() {// 수행할 내용.

});

객체로 표현하는 이유는 트랜잭션이 끝나기 전에 액티비티나 프레그먼트를 끝내야할 때 대기중인 트랜잭션을 취소하기 위해서도 사용하기 때문이다.Ex) 1. 현재 대기중인 트랜잭션이 있다고 가정하자.

2. 이 트랜잭션을 수행한 다음에는 액티비티의 TextView를 갱신한다.3. 하지만 이 트랜잭션이 수행되기 전에 액티비티를 종료하였다.4. 만약 트랜잭션이 그대로 수행된다면 존재하지 않는 메모리에 TextView에 대한

데이터 갱신 작업을 수행해야 하는 것이다. 앱이 충돌할 수 있다.

때문에 액티비티를 종료하기 전에 확인 작업을 해주어야 한다.public void onStop () {

if (transaction != null && !transaction.isCancelled()) {transaction.cancel();

}}

Realm에서 Transaction을 관리하는 법을 알아보자.

Transaction관리하기

05 Transaction

55

06쓰기

56

Realm 객체를 생성하는 법을 알아보자.객체 생성하기

1 Realm을 통해 객체 생성하기

RealmObject들은 Realm과 긴밀하게 연결되어 있기 때문에Realm을 통해 인스턴스가 생성되어야 한다.

realm.beginTransaction();User user = realm.createObject(User.class); // 새 객체 만들기user.setName("John");user.setEmail("[email protected]");realm.commitTransaction();

Realm에 의해 관리되는 객체의 데이터를 수정할 경우 Transaction 안에서 해줘야한다는 단점이 있을 수 있다.(내 생각)

06 쓰기

57

2 객체를 생성 후 Realm에 등록하기

Realm을 통해서만 객체를 생성할 때는 불편한 점이 있을 수 있다.그때는 Realm.copyToRealm() 메소드를 사용하여 등록하면 된다.

User user = new User("John");user.setEmail("[email protected]");

realm.beginTransaction();User realmUser = realm.copyToRealm(user);realm.commitTransaction();

< 중요 > copyToRealm을 사용할 때 반환되는 객체를 Realm이 관리한다. -> 원본 객체(user)의 내용을 바꿔도 Realm에 있는 데이터가 바뀌는 것이 아니다.-> Realm이 관리하는 객체(realmUser)를 바꿔야 Realm에 있는 데이터가 바뀐다.

Realm 객체를 생성하는 법을 알아보자.객체 생성하기06 쓰기

58

객체를 생성하고 쓰기를 할 때 주의할 점을 알아보자.주의 할 점

createObject를 사용하여 객체를 처음 생성할 경우 Realm은 RealmObject안에 있는 필드의 내용을 default value(쓰레기값)으로 설정을 하고 객체를 만든다.이때 객체의 필드에 PrimaryKey가 등록되어 있으면 충돌이 일어 날 수 있다.-> default value는 고정값이기 때문이다.

이를 해결하기 위해서는 비관리 객체를 생성하고 PrimaryKey에 대한 값을 설정한다음 copyToRealm을 이용해서 Realm에 등록해 주어야 한다.

User user = realm.createObject(User.class); // 필드들에 대한 값을 default value로 설정한다.// 이때 PrimaryKey에 대한 충돌이 날 수 있다.

User user = new User("John");uesr.setId(value);

realm.beginTransaction();User realmUser = realm.copyToRealm(user);realm.commitTransaction();// 이렇게 해주면 충돌을 피할 수 있다.

1 PrimaryKey 충돌

06 쓰기

59

Realm은 문자열이나 바이트 배열의 개별 요소를 갱신하는 것은 불가능하다.특정 요소를 갱신하기 위해선 아래처럼 해야한다.

realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {

bytes[] bytes = realmObject.binary;bytes[4] = 'a';realmObject.binary = bytes;

}});

2 문자열과 바이트 배열 갱신하기

Realm이 MVCC 아키텍처에 따라 기존의 데이터를 변경하는 것을 막아 다른 스레드와프로세스가 안정된 상태의 데이터를 읽기 위함이다.

객체를 생성하고 쓰기를 할 때 주의할 점을 알아보자.주의 할 점06 쓰기

60

07질의

61

Realm의 기본적인 사용법(1)

질의의 시작은 realm.where를 시작으로 하며 끝은 find(All)을 통해 끝난다.

Realm의 모든 질의는 바로 처리되지 않고 속성에 접근할 때에만 데이터를 읽는다.

API(Realm.class) Public RealmQuery<E> where(java.lang.Class<E> class);

(RealmQuery.class) Public RealmResults<E> findAll();(RealmQuery.class) Public RealmResults<E> findAllAsync();(RealmQuery.class) Public RealmResults<E> findAllSorted(String fieldName);

(RealmQuery.class) Public E findFirst();

07 질의(Query)

62

// Build the query looking at all users:RealmQuery<User> query = realm.where(User.class);

// 질의 조건을 추가합니다query.equalTo("name", "John");query.or().equalTo("name", "Peter");

// 질의를 수행합니다RealmResults<User> result1 = query.findAll();

질의를 통해 나온 결과가 RealmResults에 저장되어 나온다.이때 객체는 복사되지 않고, 레퍼런스가 저장되어 있는 RealmResult를 통해서직접적으로 다룰 수 있다.

RealmResults는 AbstractList를 상속받았기 때문에각 객체는 인덱스를 통해서 접근이 가능하다.

또한 질의에 맞는 결과가 없더라도 null을 반환하지 않고size()메소드가 0을 반환한다.

각 객체의 내용을 수정하거나 삭제할 경우 Transaction을 이용해야 한다.

Realm의 기본적인 사용법(1)07 질의(Query)

63

Realm의 기본적인 사용법(2) – Fluent interface

// 같은 일들을 한번에 합니다 ("Fluent interface"):RealmResults<User> result2 = realm.where(User.class)

.equalTo("name", "John")

.or()

.equalTo("name", "Peter")

.findAll();

RealmQuery<User> query = realm.where(User.class);

query.equalTo("name", "John");query.or().equalTo("name", "Peter");

RealmResults<User> result1 = query.findAll();

07 질의(Query)

64

Realm의 Query engine에 대해서 알아보자.Fluent interface

Realm은 Query Engine으로 Fluent interface를 사용하였다.Fluent interface란 메소드 체이닝(method chaining) 기법으로return 값으로 자기 자신 또는 다른 객체를 지정 함으로서메소드를 연속적으로 호출 할 수 있도록 하는 기법이다.

가장 쉽게 볼 수 있는 것은 자바스크립트(또는 Jquery)에서 볼 수 있다.document.getElementById("demo").innerHTML…

안드로이드에서 쉽게 볼 수 있는 곳은 Toast 부분에서이다.Toast.makeText(…).show(); (또는 스낵바)

Toast의 makeText는 return 값으로 Toast 객체를 반환한다.-> 즉 자기 자신을 반환하는 것이다. 때문에 자기 자신의 메소드를

다시 호출 할 수 있어서 메소드 체이닝이 가능하게 된다.

Realm의 Query도 이러한 구조를 띄고 있다.

07 질의(Query)

65

Realm의 Query의 몇 가지 종류를 알아보자.Query

1 조건 관련 질의대부분 이름만으로 설명이 된다.• between(), greaterThan(), lessThan(), greaterThanOrEqualTo(), lessThanOrEqualTo()

-> (필드 이름, 숫자 (, 숫자))• equalTo(), notEqualTo()

-> (필드 이름, 값)• contains(), beginsWith(), endsWith()

-> (필드 이름, 문자)• isNull(), isNotNull()

-> (필드 이름)• isEmpty(), isNotEmpty()

-> (필드 이름)

equalTo(), contains(), beginsWith(), endsWith()문자에 대한 질의 중 이 4개에 대해서는(필드 이름, 문자, case)를 통해서 대소문자를 구분의 유무를 정할 수 있다.

-> CASE.SENSITIVE , CASE.INSENSITIVE

07 질의(Query)

66

2 논리 연산자• Realm의 Query는 암묵적으로 and 연산을 가지고 있으며 or연산이필요할 때는 or연산만 명시해주면 된다.

• 그룹 조건의 연산 순서를 명시하기 위해서는 왼쪽 괄호로 beginGroup()을사용하고 오른쪽 괄호로 endGroup()을 사용한다.

• not()으로 부정 조건을 만들 수 있다. 하위 조건을 부정하기 위해서는beginGroup과 endGroup을 함께 사용해야 한다.

RealmResults<User> r = realm.where(User.class).greaterThan("age", 10) // 암묵적인 AND.beginGroup()

.equalTo("name", "Peter")

.or()

.contains("name", "Jo").endGroup().findAll();

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

67

3 결과 정렬하기RealmResults<User> result = realm.where(User.class).findAll();result = result.sort("age"); // 오름차순으로 정렬result = result.sort("age", Sort.DESCENDING); // 내림차순으로 정렬

API (RealmResults.class)

Public RealmResults<E> sort(String fieldname);Public RealmResults<E> sort(String fieldname, Sort sortOrder);Public RealmResults<E> sort(String[] fieldname, Sort[] sortOrder);Public RealmResults<E> sort(String fieldname1, Sort sortOrder1,

String fieldname2, Sort sortOrder2);

Sort.Enum - Sort.ASCENDING, Sort.DESCENDING

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

68

4 집합(arregation)

RealmResults<User> results = realm.where(User.class).findAll();

long sum = results.sum("age").longValue();long min = results.min("age").longValue();long max = results.max("age").longValue();double average = results.average("age");

long matches = results.size();

API (RealmResults.class)숫자가 저장되어 있는 필드만 지원한다.

Public Number sum(String fieldname);Public Number max(String fieldname);Public Number min(String fieldname);Public double average(String fieldname);

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

69

5 삭제(Deletion)

final RealmResults<Dog> results = realm.where(Dog.class).findAll();// 데이터에 대한 모든 변경은 트랜잭션에서 이루어져야 합니다realm.executeTransaction(new Realm.Transaction() {

@Overridepublic void execute(Realm realm) {

// 하나 맞는 데이터를 삭제합니다results.deleteFirstFromRealm();results.deleteLastFromRealm();

// 하나의 객체를 삭제합니다Dog dog = results.get(5);dog.deleteFromRealm();

// 전체 맞는 데이터를 삭제합니다results.deleteAllFromRealm();

}});

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

70

// RealmResults에서 맨 처음 객체를 삭제하거나 맨 마지막 객체를 삭제합니다.results.deleteFirstFromRealm();results.deleteLastFromRealm();

// 하나의 객체를 삭제합니다Dog dog = results.get(5);dog.deleteFromRealm();

1) 하나의 데이터를 삭제하는 방법

이렇게 할 경우 Realm에서는 실제로는 삭제가 되었지만, RealmResults에서는 삭제가 되지 않았을 수도 있다.-> 후에 RealmResults에서 삭제한 데이터가 다시 검색될 수도 있다.

// RealmResults에서 삭제를 직접한다.(realm 문서 – 질의 – 반복자 참고)results.deleteFromRealm(5);

5 삭제(Deletion)

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

71

API (RealmResults.class)

Public Boolean deleteAllFromRealm();Public Boolean deleteFristFromRealm();Public Boolean deleteLastFromRealm();Public void deleteFromRealm(int location);

API (RealmObject.class)

Public void deleteFromRealm();

5 삭제(Deletion)

2) 결과에 맞는 여러 개의 데이터를 삭제하는 방법

// RealmResults에 있는 모든 데이터를 삭제한다.results.deleteAllFromRealm();

Realm의 Query의 몇 가지 종류를 알아보자.Query07 질의(Query)

72

Realm의 비동기 질의에 대해서 알아보자.비동기 질의

Realm의 대부분의 질의는 UI스레드에서 동기적으로 처리할 수 있을 정도로충분히 빠르다.

하지만 복잡한 질의나 대규모 데이터 집합을 질의하는 경우, 백그라운드에서질의 하는 것이 더 나은 경우들이 있다.

RealmResults<User> result = realm.where(User.class).equalTo("name", "John").or().equalTo("name", "Peter").findAllAsync();

// findAll 이였던 부분을 findAllAsync로만 바꿔주면 된다.

질의는 블록되지 않고 즉시 RealmResults를 반환하는 것을 유의해야 한다.-> 표준 자바의 Future와 흡사한 구조이다. (Thread와 관련 있는 것으로 생각된다)

질의는 백그라운드에서 계속되며 한번 완료되면 반환된RealmResults 인스턴스를 갱신한다.

07 질의(Query)

73

1) 백그라운드에서 질의가 끝났는지 확인할 수 있다.

if (result.isLoaded()) {// 결과는 지금 사용할 수 있습니다

}

2) 비동기 질의를 강제적으로 동기적으로 로딩 할 수 있다.

동기적으로 획득한 RealmResults의 isLoaded()를 호출하면 항상 true를 반환한다.

result.load() // 주의하세요. 이 코드는 현재 스레드를 반환될 때까지 멈추게 합니다

3) 루퍼 스레드에서만 비동기 질의를 사용할 수 있다.비동기 질의는 결과를 일관되게 전달하기 위해 Handler를 사용한다.Looper 없이 스레드 내에서 비동기 질의를 하게 되면ILLegalStateException을 발생시킨다.

Realm의 비동기 질의에 대해서 알아보자.비동기 질의07 질의(Query)

74

08쓰레드

75

Thread에서 realm을 사용하는 방법을 알아보자.

08 쓰레드(Thread)

1 장점1) 여러 쓰레드에서 데이터를 적은 노력으로 다룰 수 있다.2) 객체와 질의에 의한 결과가 자동으로 업데이트 된다. (09-노티피케이션 참고)

2 제약사항쓰레드 간의 Realm, RealmObject, RealmResults 인스턴스는 전달될 수 없다.동일한 데이터를 여러 쓰레드에서 접근하고싶다면 새로운 Realm 인스턴스를 생성하고 (Realm.getDefualtInstance 등)질의를 통해 객체에 접근해야 한다.

* 예외 사항 *비동기 질의와 비동기 트랜잭션을 이용해서 작업을 백그라운드에 보내고작업 결과를 본래 쓰레드로 가져올 때는 예외이다.(비동기 질의와 비동기 트랜잭션을 호출한 쓰레드)

76

09노티피케이션

77

Realm에서 지원하는 알림(notification)에 대해서 알아보자.

09 노티피게이션(Notification)

1) 인스턴스로 얻어놓은 Realm, RealmObject, RealmResults에 대해서는데이터 변경에 대한 알림을 설정할 수 있다.

2) 설정하는 방법은 Change Listener를 등록하는 방법과 waitForChange()메소드를 호출하는 방법 두 가지가 있다.

3) Listener 방식은 루퍼 쓰레드에서만 동작한다.루퍼 쓰레드 밖에서는 Realm.waitForChange()를 사용한다.

4) Realm 객체의 자동 리프레쉬 기능이 활성화 되어있는지를 확인하기 위한isAutoRefresh() 메소드가 존재한다.

* 주의 사항 *Listener는 IntentService 내에서는 동작하지 않는다.(루퍼 쓰레드 이지만)

1 알림

78

Realm에서 지원하는 알림(notification)에 대해서 알아보자.

09 노티피게이션(Notification)

1) RealmChangeListener 객체를 생성하여 Realm, RealmObject, RealmResults에 등록해서 사용한다.

2) 객체나 질의 결과가 변경 될 때 리스너가 자동으로 호출되므로 재질의를할 필요가 없다.

3) 데이터를 수정하면 다음 루프 이벤트에 반영된다.4) removeChangeListener나 removeAllChangeListener를 통해서 리스너를지울 수 있다.

2 Listener

Listener

APIInterface RealmChangeListener<T>

void onChange(T element);

Public void addChangeListener(RealmChangeListener<T> listener);Public void removeChangeListener(RealmChangeListener<T> listener);Public void removeAllChangeListener();

T = Realm, ? Extends RealmObject, RealmResults

79

Realm에서 지원하는 알림(notification)에 대해서 알아보자.

09 노티피게이션(Notification) Listener

public class MyActivity extends Activity {private Realm realm;private RealmChangeListener realmListener;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);realm = Realm.getDefaultInstance();realmListener = new RealmChangeListener() {

@Overridepublic void onChange(Realm realm) {//Realm에 추가하기 위한 리스너.// .업데이트를 위해 무언가 합니다 (UI, etc.)

}};realm.addChangeListener(realmListener);

}

@Overrideprotected void onDestroy() {super.onDestroy();realm.removeChangeListener(realmListener); // 리스너를 제거합니다.realm.close(); // Realm 인스턴스를 닫습니다.

}}

80

Realm에서 지원하는 알림(notification)에 대해서 알아보자.

09 노티피게이션(Notification) Listener

private RealmChangeListener puppiesListener;private RealmChangeListener dogListener;

private RealmResults<Dog> puppies;private Dog dog;

puppiesListener = new RealmChangeListener() {@Overridepublic void onChange(RealmResults<Dog> puppies) {RealmResults<Dog>에 추가하기 위한 리스너

// ... puppies 인스턴스와 작업합니다.}

};

dogListener = new RealmChangeListener() {//RealmObject에 추가하기 위한 리스너@Overridepublic void onChange(Dog dog) {

// ... Dog 인스턴스를 업데이트하며 작업합니다.}

};

puppies.addChangeListener(puppiesListener);dog.addChangeListener(dogListener); }

81

Realm에서 지원하는 알림(notification)에 대해서 알아보자.

09 노티피게이션(Notification) Listener

참조형이 변환되었을 때도 리스너가 호출된다.

Person person = realm.where(Person.class).findFirst();person.getDogs(); // => 2 - 목록에 두마리 개가 있다고 가정합니다person.addChangeListener(new RealmChangeListener() {

@Overridepublic void onChange(Person person) {

// 사람 인스턴스의 변화에 반응합니다.// 어떤 참조된 개가 갱신되어도 반응합니다.

}});

Dog dog = person.getDogs().get(0);realm.beginTransaction();dog.setAge(5);realm.commitTransaction();// 참조된 강아지가 변경되었기 때문에 person에 추가한 리스너는 런 루프의 다음 단계에서호출됩니다.

82

10Json

83

Realm에 Json형식의 데이터를 넣는 방법을 알아보자.

10 Json

1) Json을 Realm에 직접 RealmObject로 추가하는 것이 가능하다.2) Realm은 RealmObject에 정의되지 않는 Json 프로퍼티들은 무시한다.3) 단일 객체나 객체들의 리스트를 추가할 수 있다.

API (Realm.class)

Public void createObjectFromJson(Class<E> class, String json);Public void createObjectFromJson(Class<E> class, JSONArray json);Public void createObjectFromJson(Class<E> class, InputStream inputStream);

Public void createAllFromJson(Class<E> class, String json);Public void createAllFromJson(Class<E> class, JSONArray json);Public void createAllFromJson(Class<E> class, InputStream inputStream);

Public void createOrUpdateObjectFromJson(Class<E> class, String json);Public void createOrUpdateObjectFromJson(Class<E> class, JSONArray json);Public void createOrUpdateObjectFromJson(Class<E> class, InputStream inputStream);

Public void createOrUpdateAllFromJson(Class<E> class, String json);Public void createOrUpdateAllFromJson(Class<E> class, JSONArray json);Public void createOrUpdateAllFromJson(Class<E> class, InputStream inputStream);

84

Realm에 Json형식의 데이터를 넣는 방법을 알아보자.

10 Json

public class City extends RealmObject {private String city;private int id;

}

realm.executeTransaction(new Realm.Transaction() {@Override // 문자열을 삽입합니다public void execute(Realm realm) {realm.createObjectFromJson(City.class, "{ city: \"Copenhagen\", id: 1 }");

}});

realm.executeTransaction(new Realm.Transaction() {@Override // InputStream을 이용하여 여러 아이템을 삽입합니다public void execute(Realm realm) {try {

InputStream is = new FileInputStream(new File("path_to_file"));realm.createAllFromJson(City.class, is);

} catch (IOException e) {throw new RuntimeException(e);

}}

});

예시

85

Json을 파싱하는데 있는 규칙을 알아보자.

10 Json

1) null 값을 필드로 가진 JSON으로 객체를 만들 때- 널이 허용된 필드는 기본 값으로 null을 설정한다.- 널이 허용되지 않은 필드는 예외를 던진다.

2) Null값의 필드를 가진 JSON으로 갱신 할 때- 널이 허용된 필드는 null로 설정한다.- 널이 허용되지 않은 필드는 예외를 던진다.

3) JSON이 필드가 없을 때- 널이 허용된 필드와 허용되지 않은 필드의 값 모두 그대로 둔다.

파싱규칙

86

11마이그레이션

87

Realm에서 스키마 버전을 업그레이드 했을 때 처리하는 방법에 대해서 알아보자.

11 마이그레이션(migration)

Realm은 코드에 정의된 스키마 버전과 디스크에 저장되어 있는스키마 버전이 다를 때 예외를 던진다.-> RealmConfiguration에 마이그레이션을 코드와 스키마 버전을설정함으로서 해결 할 수 있다.

RealmConfiguration config = new RealmConfiguration.Builder(context).schemaVersion(2) // 스키마가 바뀌면 값을 올려야만 합니다.migration(new MyMigration()) // 예외 발생대신에 마이그레이션을 수행하기.build()

이를 이용하면 마이그레이션 코드는 필요시 자동으로 수행된다.

이것은 앱의 버전업 등의 상황에서 데이터베이스의 구조가 바뀌는 일이일어날 수 있다. (필드의 추가, 삭제 등)이때 데이터 베이스 전체를 지우고 다시 생성할 경우 기존의 데이터가삭제되는 일이 발생한다. 이를 방지하기 위해 사용 할 수 있다.

Realm에는 데이터를 갱신하는 여러 내장 메서드를 제공한다.

88

Realm에서 스키마 버전을 업그레이드 했을 때 처리하는 방법에 대해서 알아보자.

11 마이그레이션(migration)

안드로이드에서 제공해주는 SQLiteOpenHelper 클래스와 비교해보면

핼퍼 클래스에서 제공하는 메소드인 onUpgrate메소드가 불렸을 때 하는 일과비슷하다고 할 수 있겠다.

API (SQLiteOpenHelper.class)

Public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);

SQLite를 사용 할 때 스키마의 버전이 다를 경우 onUpgrade 메소드가호출되며 그 안에 내용들을 수행하게 된다.

89

RealmMigration 클래스에 정의된 내장 메소드에 대해서 알아보자.

11 마이그레이션(migration) 내장메소드

RealmMigration migration = new RealmMigration() {@Overridepublic void migrate(DynamicRealm realm, long oldVersion, long newVersion) {

// DynamicRealm는 편집가능한 스키마를 노출합니다RealmSchema schema = realm.getSchema();

// 버전 1로 마이그레이션: 클래스를 생성합니다if (oldVersion == 0) {

schema.create("Person").addField("name", String.class).addField("age", int.class); //일반적인 필드를 추가할 때

oldVersion++;}

// 버전 2로 마이그레이션: 기본 키를 넣고 객체를 참조합니다if (oldVersion == 1) {

schema.get("Person").addField("id", long.class, FieldAttribute.PRIMARY_KEY).addRealmObjectField("favoriteDog", schema.get("Dog")) //RealmObject를 추가할 때.addRealmListField("dogs", schema.get("Dog")); //RealmList를 추가 할 때

oldVersion++;}

}}

90

RealmMigration 클래스에 정의된 내장 메소드에 대해서 알아보자.

11 마이그레이션(migration) 내장메소드

API(Realm.class)Public RealmSchema getSchema();

(RealmSchema.class)Public boolean contains(String className);Public RealmObjectSchema create(String className);Public RealmObjectSchema get(String className);Public Set<RealmObjectSchema> getAll();Public void remove(String className);Public RealmObjectSchema rename(String oldClassName, String newClassName);

(RealmObejctSchema.class)Public RealmObjectSchema addField(String fieldname, Class<?> fieldType,

FieldAttribute attributes);Public RealmObjectSchema addRealmObjectField(String fieldNmae, RealmObjectSchema objectSchema);Public RealmObjectSchema addRealmListField(String fieldNmae, RealmObjectSchema objectSchema);Public RealmObjectSchema addIndex(String fieldNmae);Public RealmObjectSchema addPrimaryKey(String fieldNmae);

Public RealmObjectSchema removeField(String fieldNmae);Public RealmObjectSchema removeindex(String fieldNmae);Public RealmObjectSchema removePrimaryKey();Etc..

91

12암호화

92

Realm을 암호화 하는 방법을 알아보자.

12 암호화(Encryption)

512비트(64바이트) 암호화 키를 전달하면 Realm 파일을 암호화 할 수 있다.

API (RealmConfiguration.Builder class)Public RealmConfiguration.Builder encryptionKey(byte[] key);

이 방법을 통해 디스크에 저장되는 데이터가 표준 AES-256 암호화를 통해투명한 방법으로 암호화, 복호화를 할 수 있다.파일을 생성할 때 같은 암호화 키를 매번 Realm 인스턴스에 제공해야한다.

RealmConfiguration config = new RealmConfiguration.Builder(context).encryptionKey(getKey()).build();

Realm realm = Realm.getInstance(config);

93

13현재 제약 사항

94

현재 버전까지의 제약사항을 알아보자.

13 현재 제약 사항(1.1.0v)

1. 클래스 이름은 57자로 제한된다.Android 버전 Realm은 class_ 접두어를 모든 클래스 이름에 추가한다.

2. 필드 이름의 길이는 63자로 제한된다.3. 중첩된 트랜잭션은 지원하지 않고 발견 시 예외 처리된다.4. String들과 byte array(byte[])는 16MB를 넘을 수 없다.

1 일반적인 제한

1. 정렬과 대소문자와 문자열의 일치는 ‘Latin Basic’, ‘Latin Supplement’,‘Latin Extended A’, ‘Latin Extended B’(UTF-8 range 0-591)만 지원한다.

2. 질의 중 equalTo, contain, endsWith, beginsWith에 대해서 대소문자를무관하게 설정하려면 영어 로케일을 써야만한다.

2 문자열에 대한 정렬과 질의

95

현재 버전까지의 제약사항을 알아보자.

13 현재 제약 사항(1.1.0v)

Realm파일은 여러 쓰레드에서 동시적으로 접근할 수 있지만 프로세스에대해서는 한번에 하나의 프로세스에서만 접근 할 수 있다.

3 여러 프로세스에서 동시 접근 불가

RealmObject는 라이브 객체이며 다른 쓰레드에서 변경이 일어나면 갱신됩니다.RealmObject.equals()를 썻을 때 ture를 리턴하는 두개의 Realm 객체는 항상같은 RealmObject.hashCode() 결과를 반환해야 하지만, 그 값은안정적이지 않으며 HashMap과 HashSet에서 키로 사용하면 안됩니다.

4 RealmObject의 hashCode

96

감사합니다.

정보 출처 : realm.ioppt템플릿 : 홍양홍삼님 블로그