Post on 11-Apr-2017
Realm�모델�객체의�특성
• 특정�객체를�상속받거나�구현해야�합니다.�
• RealmObject를�상속�
• RealmModel을�구현�(+@RealmClass)�
• 두가지�상태를�가집니다.�
• managed:�Realm에�관리되는�객체�
• unmanaged:�POJO�객체
왜�이렇게�하시는거죠?
• 아래의�이점을�위해,�하부�엔진과�실시간�연동합니다.�
• 무�복제�메커니즘�
• 실제로�사용되기�전에는�Java�세상에�데이터가�복제되지�않습니다.�
• 크로스플랫폼�호환성�
• 자동�갱신
과거�페이스북�앱의�문제점
• JSON�인코딩과�디코딩에�많은�리소스를�허비.�
• 사용되지�않은�데이터도�디코딩을�해서�Java�객체에�담았어야�함.�
• 해결책:�구글의�FlatBuffers를�쓰자.
무�복제�메커니즘
public long id() { int o = __offset(4); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
public String name() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }
ByteBuffer bb = ByteBuffer.wrap(bytes); MyObject obj = MyObject.getRootAsMyObject(bb); long id = obj.id(); String name = obj.name();
• 사용할�때만�메모리�맵에서�Java�월드로�데이터를�가져올�수�있습니다.
전통적인�수화�(Hydrate)
• 데이터베이스에서�자료를�문자열이나�기타�인코딩된�형태로�가져옵니다.�
• 파싱�혹은�디코딩을�해서�가져온�데이터를�몽땅�Java�객체에�담아줍니다.
CPU와�메모리를�낭비하는�수화
• 데이터베이스에서�자료를�문자열이나�기타�인코딩된�형태로�가져옵니다.�
• 쓰지도�않은�데이터도�다�가져오고�변환까지�거쳤어요.�
• 파싱�혹은�디코딩을�해서�가져온�데이터를�몽땅�Java�객체의�필드�담아줍니다.�
• 쓰지도�않을�데이터를�전부�다시�변환하고�몽땅�필드에�담았어요.�
name setName getName
RealmObject
realmGet$name realmSet$name RealmProxyObject
RealmProxyObject
• Annotation�Processing�Tool이�이�작업을�대신해줍니다.
getSupportedOptions getSupportedAnnotationTypes getSupportedSourceVersion
init process
getCompletion
Processor
process 제외 구현 AbstractProcessor
APT�기본�객체
APT만으로는�부족합니다.
• APT는�객체를�생성할�수�만�있다.�
• 기존의�객체를�상속받아�확장할�수만�있고�자체를�변경할�수�없음.�
• Realm은�객체의�게터�/�세터를�Realm의�게터�/�세터로�바꾸어야�함.�
• 커스텀�게터와�세트는�동작을�어떻게�확인하고�Realm�게터�/�세터를�적절히�집어넣지?
버전�1.X�시절의�Realm
• 게터와�세터는�표준�이름으로만�생성.�(APT가�예상할�수�없음.)�
• 게터와�세터는�표준�동작만�한다고�가정.�
• 다른�메서드들도�필드에�대해�직접�접근하지�말아야�함.
바이트�코드를�변경하는�것이�해결책
• 바이트�코드를�변경합니다.�
• 필드에�읽으면�그�대신�Realm의�게터를�호출�
• 필드에�무엇을�쓰면�대신�Realm의�세터를�호출�
• 참�쉽죠?
트랜스포머�API
• 안드로이드�그래들�플러그인의�공식적인�후�가공�방법
dependencies에�트랜스포머�등록
android.registerTransform으로트랜스�폼을�빌드�과정에�포함.
왜�이래요?
• 아래의�이점을�위해,�하부�엔진과�실시간�연동합니다.�
• 무�복제�메커니즘�
• 크로스플랫폼�호환성�
• Android,�iOS,�Xamarin,�Javascript에서�호환성을�가집니다.�
• 자동�갱신
왜�이래요?
• 아래의�이점을�위해,�하부�엔진과�실시간�연동합니다.�
• 무�복제�메커니즘�
• 크로스플랫폼�호환성�
• 자동�갱신�
• 자료는�다른�곳에서�갱신되면�자동으로�갱신이�이루어집니다.
add
Blah�blah…
Blah�blah…
Blah�blah…
Blah�blah…
Blah�blah…
Blah�blah…
Blah�blah…
Hello
데이터를�추가하면�리스트�뷰는�자동으로�갱신합니다.데이터는�자동으로�갱신되고�알림이�전달됨�->�알림�때마다�UI를�새로그림.
Realm�객체�생성.
• copyToRealm(object)�-�POJO�인스턴스를�복사�managed�인스턴스�생성.�
• Realm.createObject(class)�-�새로운�managed�인스턴스�생성.Realm.createObject(class,�pk)
• 현재�스키마에서�클래스를�이용해서�테이블을�가져옴.�
• 테이블에서�열을�만들어�가져오고.�
• get을�이용해서�managed�객체를�반환.
��������Table�table�=�schema.getTable(clazz);���������long�rowIndex�=�table.addEmptyRowWithPrimaryKey(primaryKeyValue);���������return�get(clazz,�rowIndex,�acceptDefaultValue,�excludeFields);
Realm.createObject
Schema�(모델과�연관된�RealmObjectSchema와�Table을�관리)
K: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchema
K: RealmModel V: TableK: RealmModel V: TableK: RealmModel V: TableK: RealmModel V: TableK: RealmModel V: Table
K: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: RealmModel V: RealmObjectSchemasK: modelName V: RealmObjectSchema
K: RealmModel V: TableK: RealmModel V: TableK: RealmModel V: TableK: RealmModel V: TableK: modelName V: Table
Table�(실제�스토리지와�연관된�객체)
• addColumn�/�removeColumn�/�renameColumn�…�• addEmptyRow�/�addEmptyRows�/�add�…�• getPrimaryKey�/�hasPrimaryKey�/�isPrimaryKey�…�• getLong(column,�row)�/�getBoolean(column,�row)�…�• findFirstLong(column,�long)�/�findFirstBoolean(column,�boolean)…
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
이름으로�조회했습니다.
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
이메일로�조회했습니다.
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
전통적인�데이타베이스는�한줄�씩�저장합니다.�->�캐쉬�미스
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
�한줄�씩�저장하면�용량이�맞지�않아서�패딩도�넣어야�합니다.
인덱스 이름 이메일 전화번호
1 디카프리오 d@realm.io 1004
2 디아즈 da@realm.io 1005
3 게이츠 g@realm.io 1006
4 갓민우 1@realm.io 1007
한줄씩�저장하면�캐쉬히트율이�높고�패딩이�필요없어요.
각기�다른��스레드�로컬을�가집니다.
A
B C
D
F G
E
H I
E’
H’
C’
A’
유저�3:버전�2�쓰기중유저�2:�버전�1�읽기�중
유저�1:�버전�1�읽기�중스레드 로컬 1: 버전 1
스레드 로컬 2: 버전 1
스레드 로컬 3: 버전 1 -> 2
혼란스러울�수�있는�스레드�로컬
• 배타적이지�않게�효율적으로�읽기,�쓰기를�하기�위해메타�데이터를�스레드�단위로�저장.�
• 메모리�맵으로�연결된�데이터는�멀티�스레드로�공유되고�있음.�
• 다만�스레드�로컬로�열린�Realm,�RealmList,�RealmResults,�RealmObjects�객체를�다른�스레드로�전달할�수�없음.�
• 다른�스레드에서�쿼리를�하면�멀티�스레드�자료�공유�덕에�바로�읽음.
Gradle�Plugin
• 환경별로�어노테이션�설치는�사용자에게�어렵다.�
• annotationProcessor�-�안드로이드�그래들�플러그인�2.2�이상만�가능.�
• kapt�-�코틀린.�
• apt�-�android-apt를�설치해야�함.�
• 싱크�기능,�어노테이션�전용�코드를�앱�빌드에서�빼기는�사용자에게�어렵다.