Slide 1

Slide 1 text

Sociomantic Labs Dev Fest Hamburg 2016 #devfestHH Droidcon Vienna 2016 #droidconVie Viraj Tank @viraj49 Droidcon London 2016 #droidconUK Mobile Era Oslo 2016 #mobileEra

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

SQLite Realm Wrapper, ORM 2000, 2008 2008 - now 2014 DB History

Slide 4

Slide 4 text

Object store getA().getB() getA().getC()

Slide 5

Slide 5 text

Operation ORMLite Realm Init 92 ms 30 ms Write - 20k 1692 ms 1011 ms Read - 2k 2716 ms 410 ms Performance

Slide 6

Slide 6 text

AES-256 Performance Security

Slide 7

Slide 7 text

Performance Security Boilerplate code

Slide 8

Slide 8 text

Performance Security Boilerplate code Documentation

Slide 9

Slide 9 text

Performance Security Boilerplate code Documentation Learning Curve

Slide 10

Slide 10 text

Sample App

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Download /* Project level build.gradle file */ classpath "io.realm:realm-gradle-plugin:2.1.1" /* Application level build.gradle file */ apply plugin: 'realm-android' ~1750 method counts ~800 kilobytes

Slide 13

Slide 13 text

Cross-platform

Slide 14

Slide 14 text

Realm + Android APK APK APK

Slide 15

Slide 15 text

Init & Config Realm.init(this); RealmConfiguration config = new RealmConfiguration .Builder() .build(); Realm.init(this); RealmConfiguration config = new RealmConfiguration .Builder() .name("gitHubDB") .build(); Realm.init(this); RealmConfiguration config = new RealmConfiguration .Builder() .name("gitHubDB") .encryptionKey(key) .build(); Realm.init(this); RealmConfiguration config = new RealmConfiguration .Builder() .name("gitHubDB") .encryptionKey(key) .deleteRealmIfMigrationNeeded() .build(); Realm.init(this); RealmConfiguration config = new RealmConfiguration .Builder() .name("gitHubDB") .encryptionKey(key) .deleteRealmIfMigrationNeeded() .build(); Realm.setDefaultConfiguration(config); Realm realm = Realm.getDefaultInstance();

Slide 16

Slide 16 text

/* used for all (realm + json + view) */ @Getter public class GitHubUser { private String login; private int id; private String avatar_url; } /* used for all (realm + json + view) */ @Getter public class GitHubUser extends RealmObject { private String login; private int id; private String avatar_url; } /* used for all (realm + json + view) */ @Getter public class GitHubUser extends RealmObject { @PrimaryKey private String login; private int id; private String avatar_url; } Model

Slide 17

Slide 17 text

MVP (model view presenter ) Clean architecture Realm + RxJava Retrofit Dagger Butterknife Retrolambda Lombok

Slide 18

Slide 18 text

Code structure

Slide 19

Slide 19 text

View public class View extends Fragment { private Presenter mPresenter; }

Slide 20

Slide 20 text

Presenter public class Presenter { private View mView; public class Presenter { private View mView; private DataSource mDataSource; public class Presenter { private View mView; private DataSource mDataSource; public void loadData() { mDataSource .getData() public class Presenter { private View mView; private DataSource mDataSource; public void loadData() { mDataSource .getData() .subscribeOn(computationThread()) public class Presenter { private View mView; private DataSource mDataSource; public void loadData() { mDataSource .getData() .subscribeOn(computationThread()) .observeOn(mainThread()) public class Presenter { private View mView; private DataSource mDataSource; public void loadData() { mDataSource .getData() .subscribeOn(computationThread()) .observeOn(mainThread()) .subscribe(mData -> mView.setData(mData)); } }

Slide 21

Slide 21 text

public class DataSource { private Cache mCache; private Dao mDao; private Retrofit mRetrofit; public class DataSource { private Cache mCache; private Dao mDao; private Retrofit mRetrofit; private Observable> fromCache() { return Observable.fromCallable(() -> mCache.getData()); } public class DataSource { private Cache mCache; private Dao mDao; private Retrofit mRetrofit; private Observable> fromCache() { return Observable.fromCallable(() -> mCache.getData()); } private Observable> fromRealm() { return Observalbe.fromCallable(() -> mDao.getData()); } public class DataSource { private Cache mCache; private Dao mDao; private Retrofit mRetrofit; private Observable> fromCache() { return Observable.fromCallable(() -> mCache.getData()); } private Observable> fromRealm() { return Observalbe.fromCallable(() -> mDao.getData()); } private Observable> fromRetrofit() { List gitHubUserList = mRetrofit.getData(); mDao.storeData(gitHubUserList); return Observable.just(gitHubUserList); } } Data Source

Slide 22

Slide 22 text

DAO public class Dao { Realm mRealm; public class Dao { Realm mRealm; public List getData() { public class Dao { Realm mRealm; public List getData() { return mRealm public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class) public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class).findAll(); } public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class).findAll(); } public void storeData(List gitHubUserList) { public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class).findAll(); } public void storeData(List gitHubUserList) { mRealm.executeTransaction(mRealm1 -> public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class).findAll(); } public void storeData(List gitHubUserList) { mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); }

Slide 23

Slide 23 text

“ Realm access from incorrect t hread. Realm objects can only b e accessed on the thread they w ere created.

Slide 24

Slide 24 text

“ I don't like you anymore.

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

DAO public class Dao { Realm mRealm; public List getData() { return mRealm.where(GitHubUser.class).findAll(); } public void storeData(List gitHubUserList) { mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); }

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Thread safety Thread- 1 Thread- 2 read write/edit/delete

Slide 29

Slide 29 text

MVCC

Slide 30

Slide 30 text

Zero copy

Slide 31

Slide 31 text

Drawing Board 1. Don't inject Realm 2. Don't pass RealmResults across threads “ Make an in memory copy of results and pass it to Presenter. - Safe integration “ Query the data in Presenter itself on main thread. - Deep integration

Slide 32

Slide 32 text

Safe integration

Slide 33

Slide 33 text

DAO public class Dao { public void storeData(List gitHubUserList) { public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public List getData() { public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public List getData() { Realm mRealm = Realm.getDefaultInstance(); public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public List getData() { Realm mRealm = Realm.getDefaultInstance(); List gitHubUserList = mRealm.where(GitHubUser.class) .findAll()); public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public List getData() { Realm mRealm = Realm.getDefaultInstance(); List gitHubUserList = mRealm.copyFromRealm( mRealm.where(GitHubUser.class) .findAll()); public class Dao { public void storeData(List gitHubUserList) { Realm mRealm = Realm.getDefaultInstance(); mRealm.executeTransaction(mRealm1 -> mRealm1.insertOrUpdate(gitHubUserList)); mRealm.close(); } public List getData() { Realm mRealm = Realm.getDefaultInstance(); List gitHubUserList = mRealm.copyFromRealm( mRealm.where(GitHubUser.class) .findAll()); mRealm.close(); return gitHubUserList; } }

Slide 34

Slide 34 text

Release time

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Drawing Board “ EventBus “ RxJava

Slide 37

Slide 37 text

Auto update 1 2 read write/edit/delete change

Slide 38

Slide 38 text

Deep integration

Slide 39

Slide 39 text

public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) .filter(realmResults -> realmResults.size() > 0) .subscribe(gitHubUsers -> mView.setData(gitHubUsers)); } public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) .filter(realmResults -> realmResults.size() > 0) .subscribe(gitHubUsers -> mView.setData(gitHubUsers)); } public void loadData() { mDataSource .getData() .subscribeOn(getComputationThread()) .observeOn(getMainThread()) public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) .filter(realmResults -> realmResults.size() > 0) .subscribe(gitHubUsers -> mView.setData(gitHubUsers)); } public void loadData() { mDataSource .getData() .subscribeOn(getComputationThread()) .observeOn(getMainThread()) .subscribe(statusValue -> statusValue); } public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) .filter(realmResults -> realmResults.size() > 0) .subscribe(gitHubUsers -> mView.setData(gitHubUsers)); } public void loadData() { mDataSource .getData() .subscribeOn(getComputationThread()) .observeOn(getMainThread()) .subscribe(statusValue -> statusValue); } public void unSubscribe() { public class Presenter { private View mView; private Realm mRealm; private DataSource mDataSource; public void bind() { mRealm = Realm.getDefaultInstance(); mRealm.where(GitHubUser.class) .findAllAsync() .asObservable() .filter(RealmResults::isLoaded) .filter(RealmResults::isValid) .filter(realmResults -> realmResults.size() > 0) .subscribe(gitHubUsers -> mView.setData(gitHubUsers)); } public void loadData() { mDataSource .getData() .subscribeOn(getComputationThread()) .observeOn(getMainThread()) .subscribe(statusValue -> statusValue); } public void unSubscribe() { mRealm.removeAllChangeListeners(); mRealm.close(); } }

Slide 40

Slide 40 text

Safe 1. Easy 2. Realm on comp-thread 3. Pluggable module 4. Easy to test & debug 5. Minimal structure change 6. Minimal refactoring 7. Clean Architechture Deep 1. Auto update feature 2. Faster queries 3. Less memory utilization Integration

Slide 41

Slide 41 text

Rule of Thumb

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Thanks github.com/viraj49 twitter.com/viraj49