SlideShare une entreprise Scribd logo
1  sur  55
Télécharger pour lire hors ligne
Painless Persistence
on Android
Christian Melchior
@chrmelchior
cm@realm.io
Why design for offline?
• A better USER EXPERIENCE!
• You always have something to show the user
• Reduce network requests and data transferred
• Saves battery
Designing for Offline
Offline architecture
MVVM
MVP
MVC
VIPER
Flux
Clean
Architecture
?
?
? ?
?
?
?
?
?
?
?
?
??
??
They all have a model
MVVM
MVP
MVC
VIPER
Flux
Clean
Architecture
ModelView
getData()
data
You’re doing it wrong!
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);



// Setup initial views

setContentView(R.layout.activity_main);



// Load data and show it

Retrofit retrofit = new Retrofit.Builder()

.addConverterFactory(JacksonConverterFactory.create())

.baseUrl("http://api.nytimes.com/")

.build();



service = retrofit.create(NYTimesService.class);

service.topStories("home", "my-key").enqueue(new Callback<NYTimesResponse<List<NYTimesStory>>>() {

@Override

public void onResponse(Response<NYTimesResponse<List<NYTimesStory>>> response, Retrofit retrofit) {

showList(response);

}



@Override

public void onFailure(Throwable t) {

showError(t);

}

});

}

You’re doing it right!
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);



// Setup initial views

setContentView(R.layout.activity_main);



// Load data and show it

Model model = ((MyApplication) getApplicationContext()).getModel();

model.getTopStories(new Observer() {

@Override

public void update(Observable observable, NYTimesResponse<List<NYTimesStory>> data) {

showList(data);

}

});

}

Encapsulate data
ModelView
Cache
Database
Network
Repository pattern
ModelView
Cache
Database
Network
Repository
Business rules
Creating/
fetching data
Repository pattern
• Repository only has CRUD methods:
• Create()
• Read()
• Update()
• Delete()
• Model and Repository can be tested separately.
Designing for offline
Repository… DatastoregetData()
Observable<Data>()
Network
Update?
Save
Designing for offline
• Encapsulate data access
• The datastore is single-source-of-truth
• Everything is asynchronous
• Observer pattern
• RxJava
• EventBus
• Testing becomes easier
Persisting data
File system
• Define hierarchy using folders
• No help from the framework
• Use cases: Images, JSON blobs
File system
// App internal files

context.getFilesDir();

context.getCacheDir();



// App external files

context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);

context.getExternalCacheDir();



// SD Card

Environment.getExternalStorageDirectory();

SharedPreferences
• Key-value store
• Simple XML file
• Use cases: Settings, Key/Value data
• Simple API’s and easy to use
SharedPreferences
// Save data

SharedPreferences pref = getPreferences(MODE_PRIVATE);

SharedPreferences.Editor editor = pref.edit();

editor.putBoolean("key", true);

editor.commit();

// Read data
boolean data = pref.getBoolean("key", false);

Databases
• Use cases: Structured data sets
• Advanced composing and query capabilities
• Complex API’s
SQLite vs. the World
• SQLite (Relational)
• Realm (Object store)
• Firebase (Document oriented)
• Couchbase Lite (Document oriented)
• Parse (Document oriented)
The Relational Model
Relational data
Relational data
BCNF
Relational data
Relational data
m:n?
Relational data
Relational data
SELECT owner.name, dog.name, city.name


FROM owner

INNER JOIN dog ON owner.dog_id = dog.id

INNER JOIN city ON owner.city_id = city.id

WHERE owner.name = 'Frank'
SQLite
String query = "SELECT " + Owner.NAME + ", " + Dog.NAME + ", " + City.NAME


+ " FROM " + Owner.TABLE_NAME

+ " INNER JOIN " + Dog.TABLE_NAME + " ON " + Owner.DOG_ID + " = " + Dog.ID

+ " INNER JOIN " + City.TABLE_NAME + " ON " + Owner.CITY_ID + " = " + City.ID

+ " WHERE " + Owner.NAME = "'" + escape(queryName) + "'";

SQLite
“Lets use an ORM”
Abstract the problem away
–Joel Spolsky
“All non-trivial abstractions, to some degree,
are leaky.”
Solved problem?
• ActiveRecord
• Androrm
• Blurb
• Cupboard
• DBFlow
• DBQuery
• DBTools
• EasyliteOrm
• GreenDAO
• Ollie
• Orman
• OrmLite
• Persistence
• RushORM
• Shillelagh
• Sprinkles
• SquiDB
• SugarORM
Realm?
Object Store
A
B C
D E F
G
VS
x
z
y
x y z
SELECT table1.x, table2.y, table3.z

FROM table1

INNER JOIN table2 ON table1.table2_id = table1.id

INNER JOIN table3 ON table1.table3_id = table3.id

References in SQL
A
B C
D E F
G
Realm.getA().getC().getF()
Object Store references
Zero-copy
	
  Person	
  {	
  
• name	
  =	
  Tommy	
  
• age	
  =	
  8	
  
• dog	
  =	
  {	
  
• name	
  =	
  Lassie	
  	
  
	
  	
  	
  }	
  
	
  }
	
  Person	
  {	
  
• name	
  =	
  Tommy	
  
• age	
  =	
  8	
  
• dog	
  =	
  {	
  
• name	
  =	
  Lassie	
  	
  
	
  	
  	
  }	
  
	
  }
	
  Person	
  {	
  
• name	
  =	
  Tommy	
  
• age	
  =	
  8	
  
• dog	
  =	
  {	
  
• name	
  =	
  Lassie	
  	
  
	
  	
  	
  }	
  
	
  }
	
  PersonProxy	
  {	
  
• name	
  
• age	
  
• dog	
  	
  
	
  }
	
  PersonProxy	
  {	
  
• name	
  
• age	
  
• dog	
  	
  
	
  }
	
  Person	
  {	
  
• name	
  =	
  Tommy	
  
• age	
  =	
  8	
  
• dog	
  =	
  {	
  
• name	
  =	
  Lassie	
  	
  
	
  	
  	
  }	
  
	
  }
Realm
ORM Realm
SQLite
Benchmarks
http://static.realm.io/downloads/java/android-benchmark.zip
1.09%
2.26%
3.79%
4.55%
22.85%
13.37%
1% 1% 1% 1% 1% 1%
0%
5%
10%
15%
20%
25%
BatchWrite% SimpleWrite% SimpleQuery% FullScan% Sum% Count%
Speedup&vs.&SQLite&
Tests&/&1000&objects&
Realm%
SQLite%
SQLite vs. Realm
• Part of Android
• Relational data model
• Based on SQL
• Public Domain
• One of the most tested pieces of software
• Need to map between SQL and Java
objects (manually or ORM).
• Foreign collections is an unsolvable
problem.
• Complex API’s
• Objects all the way down
• Zero copy architecture
• Cross-platform
• Supports encryption out of the box
• Open source*
• Custom query language
• Will add ~2500 methods + 800 kB of native
code.
• Still in beta
“Talk is cheap. Show
me the code.”
–Linus Torvalds
Adding Realm
// ./build.gradle

buildscript {

repositories {

jcenter()

}

dependencies {

classpath 'com.android.tools.build:gradle:2.0.0-alpha1'

classpath 'io.realm:realm-gradle-plugin:0.86.0'

}

}

// ./app/build.gradle

apply plugin: 'com.android.application'

apply plugin: 'realm'

Models and Schema
public class Person extends RealmObject {

private String name;

private int age;

private Dog dog;

private RealmList<Cat> cats;
// Autogenerated getters/setters

}
public class Cat extends RealmObject {

private String name;

// Autogenerated getters/setters

}
public class Dog extends RealmObject {

private String name;

// Autogenerated getters/setters

}
Getting an Realm instance
// Default configuration. Schema is automatically detected
RealmConfiguration config = new RealmConfiguration.Builder(context).build();

Realm.setDefaultConfiguration(config);

Realm realm = Realm.getDefaultInstance();



Create objects - Realm
// Create and set persisted objects

realm.beginTransaction();

Person person = realm.createObject(Person.class);

person.setName("Young Person");

person.setAge(14);

realm.commitTransaction();

// Copy java objects

Person person = new Person();

person.setName("Young Person");

person.setAge(14);



realm.beginTransaction();

realm.copyToRealm(person);

realm.commitTransaction();

• Extend RealmObject
• POJO: Plain Old Java Object
Transactions - Realm
// Simple writes

realm.beginTransaction();

// ...

realm.commitTransaction();

// Automatically handle begin/commit/cancel

realm.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

// ...

}

});

Queries
RealmResults<Person> results = realm.where(Person.class)
.equalTo("age", 99)
.findAll();

RealmResults<Person> results = realm.where(Person.class)
.equalTo("cats.name", “Tiger")
.findAll();

RealmResults<Person> results = realm.where(Person.class)
.beginsWith("name", “John")
.findAllAsync();

results.addChangeListener(new RealmChangeListener() {

@Override

public void onChange() {

showResults(results);

}

});

• Fluent queries
• Semi-typesafe
• Easy async
• Always up-to-date
Network data
// Use Retrofit to parse objects

Retrofit retrofit = new Retrofit.Builder()

.addConverterFactory(JacksonConverterFactory.create())

.baseUrl("http://api.nytimes.com/")

.build();



MyRestApi service = retrofit.create(MyRestApi.class);

final Data data = service.getData();



// Copy all data into Realm

realm.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

realm.copyToRealmOrUpdate(data);

}

});

RxJava (Realm)
Observable<Realm> observableRealm = realm.asObservable();

Observable<RealmResults<Person>> results = realm.where(Person.class)
.beginsWith("name", “John")
.findAllAsync()
.asObservable();

Observable<Person> results = realm.where(Person.class).findFirst().asObservable();

Observable<RealmQuery> results = realm.where(Person.class).asObservable();

Example
https://github.com/realm/realm-java/tree/cm/offline-
newsreader/examples/newsreaderExample
Take aways
• Not everyone is on Wifi or 4G networks
• Encapsulate data access
• Designing for offline gives a a better USER
EXPERIENCE!
Resources
• Repository Pattern: http://martinfowler.com/eaaCatalog/
repository.html
• Design for offline: https://plus.google.com/
+AndroidDevelopers/posts/3C4GPowmWLb
• MVP example: https://www.code-labs.io/codelabs/
android-testing/#0
• Optimizing network requests: https://www.youtube.com/
playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE
• Realm : https://realm.io/docs/java/latest/
Questions?
@chrmelchior
cm@realm.io
We are hiring
https://realm.io/jobs/

Contenu connexe

Tendances

Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmYusuke Kita
 
Akka and the Zen of Reactive System Design
Akka and the Zen of Reactive System DesignAkka and the Zen of Reactive System Design
Akka and the Zen of Reactive System DesignLightbend
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KThomas Fuchs
 
Crafting Evolvable Api Responses
Crafting Evolvable Api ResponsesCrafting Evolvable Api Responses
Crafting Evolvable Api Responsesdarrelmiller71
 
ElasticSearch for .NET Developers
ElasticSearch for .NET DevelopersElasticSearch for .NET Developers
ElasticSearch for .NET DevelopersBen van Mol
 
Building an aws sdk for Perl - Granada Perl Workshop 2014
Building an aws sdk for Perl - Granada Perl Workshop 2014Building an aws sdk for Perl - Granada Perl Workshop 2014
Building an aws sdk for Perl - Granada Perl Workshop 2014Jose Luis Martínez
 
Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Jose Luis Martínez
 
Кирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, CiklumКирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, CiklumAlina Vilk
 
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun..."ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...Julia Cherniak
 
Restful App Engine
Restful App EngineRestful App Engine
Restful App EngineRyan Morlok
 
Intro to React
Intro to ReactIntro to React
Intro to ReactTroy Miles
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Sven Efftinge
 
Scala.js for large and complex frontend apps
Scala.js for large and complex frontend appsScala.js for large and complex frontend apps
Scala.js for large and complex frontend appsOtto Chrons
 
Fast C++ Web Servers
Fast C++ Web ServersFast C++ Web Servers
Fast C++ Web ServersTroy Miles
 
Paws: A Perl AWS SDK - YAPC Europe 2015
Paws: A Perl AWS SDK - YAPC Europe 2015Paws: A Perl AWS SDK - YAPC Europe 2015
Paws: A Perl AWS SDK - YAPC Europe 2015CAPSiDE
 

Tendances (20)

Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in Realm
 
Akka and the Zen of Reactive System Design
Akka and the Zen of Reactive System DesignAkka and the Zen of Reactive System Design
Akka and the Zen of Reactive System Design
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 
Crafting Evolvable Api Responses
Crafting Evolvable Api ResponsesCrafting Evolvable Api Responses
Crafting Evolvable Api Responses
 
ElasticSearch for .NET Developers
ElasticSearch for .NET DevelopersElasticSearch for .NET Developers
ElasticSearch for .NET Developers
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Building an aws sdk for Perl - Granada Perl Workshop 2014
Building an aws sdk for Perl - Granada Perl Workshop 2014Building an aws sdk for Perl - Granada Perl Workshop 2014
Building an aws sdk for Perl - Granada Perl Workshop 2014
 
Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015Paws - Perl AWS SDK Update - November 2015
Paws - Perl AWS SDK Update - November 2015
 
Paws - A Perl AWS SDK
Paws - A Perl AWS SDKPaws - A Perl AWS SDK
Paws - A Perl AWS SDK
 
Кирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, CiklumКирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, Ciklum
 
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun..."ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
 
Realm database
Realm databaseRealm database
Realm database
 
Restful App Engine
Restful App EngineRestful App Engine
Restful App Engine
 
Intro to React
Intro to ReactIntro to React
Intro to React
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
 
Scala.js for large and complex frontend apps
Scala.js for large and complex frontend appsScala.js for large and complex frontend apps
Scala.js for large and complex frontend apps
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
Fast C++ Web Servers
Fast C++ Web ServersFast C++ Web Servers
Fast C++ Web Servers
 
Paws: A Perl AWS SDK - YAPC Europe 2015
Paws: A Perl AWS SDK - YAPC Europe 2015Paws: A Perl AWS SDK - YAPC Europe 2015
Paws: A Perl AWS SDK - YAPC Europe 2015
 

En vedette

Android custom listview
Android custom listviewAndroid custom listview
Android custom listviewparmistech
 
Android Architecture MVP Pattern
Android Architecture MVP Pattern Android Architecture MVP Pattern
Android Architecture MVP Pattern Jeff Potter
 
Persistence in Android
Persistence in AndroidPersistence in Android
Persistence in Androidma-polimi
 
Open Ldap Integration and Configuration with Lifray 6.2
Open Ldap Integration and Configuration with Lifray 6.2Open Ldap Integration and Configuration with Lifray 6.2
Open Ldap Integration and Configuration with Lifray 6.2Vinaykumar Hebballi
 
Android Life Cycle
Android Life CycleAndroid Life Cycle
Android Life Cyclemssaman
 
Android development - ListView & Adapter
Android development - ListView & AdapterAndroid development - ListView & Adapter
Android development - ListView & AdapterLope Emano
 
Android life cycle
Android life cycleAndroid life cycle
Android life cycle瑋琮 林
 
Realm: 초고속 데이터베이스
Realm: 초고속 데이터베이스Realm: 초고속 데이터베이스
Realm: 초고속 데이터베이스Leonardo YongUk Kim
 
Android lifecycle
Android lifecycleAndroid lifecycle
Android lifecycleKumar
 
Introduction to Listview in Android
Introduction to Listview in AndroidIntroduction to Listview in Android
Introduction to Listview in Androidtechnoguff
 
ListView and Custom ListView on Android Development [Thai]
ListView and Custom ListView on Android Development [Thai]ListView and Custom ListView on Android Development [Thai]
ListView and Custom ListView on Android Development [Thai]Somkiat Khitwongwattana
 
Android activity lifecycle
Android activity lifecycleAndroid activity lifecycle
Android activity lifecycleSoham Patel
 
Realm: Building a mobile database
Realm: Building a mobile databaseRealm: Building a mobile database
Realm: Building a mobile databaseChristian Melchior
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 

En vedette (20)

Json vs Gson vs Jackson
Json vs Gson vs JacksonJson vs Gson vs Jackson
Json vs Gson vs Jackson
 
Product director
Product directorProduct director
Product director
 
Android custom listview
Android custom listviewAndroid custom listview
Android custom listview
 
Android Data Persistence
Android Data PersistenceAndroid Data Persistence
Android Data Persistence
 
Android Architecture MVP Pattern
Android Architecture MVP Pattern Android Architecture MVP Pattern
Android Architecture MVP Pattern
 
Persistence in Android
Persistence in AndroidPersistence in Android
Persistence in Android
 
Android Custom view
Android Custom view Android Custom view
Android Custom view
 
Google android Activity lifecycle
Google android Activity lifecycle Google android Activity lifecycle
Google android Activity lifecycle
 
Open Ldap Integration and Configuration with Lifray 6.2
Open Ldap Integration and Configuration with Lifray 6.2Open Ldap Integration and Configuration with Lifray 6.2
Open Ldap Integration and Configuration with Lifray 6.2
 
Android Life Cycle
Android Life CycleAndroid Life Cycle
Android Life Cycle
 
Android development - ListView & Adapter
Android development - ListView & AdapterAndroid development - ListView & Adapter
Android development - ListView & Adapter
 
Android life cycle
Android life cycleAndroid life cycle
Android life cycle
 
Realm: 초고속 데이터베이스
Realm: 초고속 데이터베이스Realm: 초고속 데이터베이스
Realm: 초고속 데이터베이스
 
Android lifecycle
Android lifecycleAndroid lifecycle
Android lifecycle
 
Introduction to Listview in Android
Introduction to Listview in AndroidIntroduction to Listview in Android
Introduction to Listview in Android
 
ListView and Custom ListView on Android Development [Thai]
ListView and Custom ListView on Android Development [Thai]ListView and Custom ListView on Android Development [Thai]
ListView and Custom ListView on Android Development [Thai]
 
Android activity lifecycle
Android activity lifecycleAndroid activity lifecycle
Android activity lifecycle
 
Realm: Building a mobile database
Realm: Building a mobile databaseRealm: Building a mobile database
Realm: Building a mobile database
 
Effective Android UI - English
Effective Android UI - EnglishEffective Android UI - English
Effective Android UI - English
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 

Similaire à Painless Persistence in a Disconnected World

Art of Javascript
Art of JavascriptArt of Javascript
Art of JavascriptTarek Yehia
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Amazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersAmazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersJeremy Lindblom
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)Doris Chen
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery EssentialsMark Rackley
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代Shengyou Fan
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...SPTechCon
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011Nick Sieger
 
前端MVC之BackboneJS
前端MVC之BackboneJS前端MVC之BackboneJS
前端MVC之BackboneJSZhang Xiaoxue
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLAll Things Open
 
fuser interface-development-using-jquery
fuser interface-development-using-jqueryfuser interface-development-using-jquery
fuser interface-development-using-jqueryKostas Mavridis
 
Swift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSwift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSimonPilkington8
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecturepostrational
 

Similaire à Painless Persistence in a Disconnected World (20)

Art of Javascript
Art of JavascriptArt of Javascript
Art of Javascript
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Amazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersAmazon Web Services for PHP Developers
Amazon Web Services for PHP Developers
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
Full Stack Scala
Full Stack ScalaFull Stack Scala
Full Stack Scala
 
Real World MVC
Real World MVCReal World MVC
Real World MVC
 
Linq
LinqLinq
Linq
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery Essentials
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
前端MVC之BackboneJS
前端MVC之BackboneJS前端MVC之BackboneJS
前端MVC之BackboneJS
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQL
 
fuser interface-development-using-jquery
fuser interface-development-using-jqueryfuser interface-development-using-jquery
fuser interface-development-using-jquery
 
ERRest and Dojo
ERRest and DojoERRest and Dojo
ERRest and Dojo
 
Swift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSwift Micro-services and AWS Technologies
Swift Micro-services and AWS Technologies
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecture
 

Dernier

Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 

Dernier (20)

Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 

Painless Persistence in a Disconnected World

  • 1. Painless Persistence on Android Christian Melchior @chrmelchior cm@realm.io
  • 2.
  • 3.
  • 4.
  • 5. Why design for offline? • A better USER EXPERIENCE! • You always have something to show the user • Reduce network requests and data transferred • Saves battery
  • 8. They all have a model MVVM MVP MVC VIPER Flux Clean Architecture ModelView getData() data
  • 9. You’re doing it wrong! @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 // Setup initial views
 setContentView(R.layout.activity_main);
 
 // Load data and show it
 Retrofit retrofit = new Retrofit.Builder()
 .addConverterFactory(JacksonConverterFactory.create())
 .baseUrl("http://api.nytimes.com/")
 .build();
 
 service = retrofit.create(NYTimesService.class);
 service.topStories("home", "my-key").enqueue(new Callback<NYTimesResponse<List<NYTimesStory>>>() {
 @Override
 public void onResponse(Response<NYTimesResponse<List<NYTimesStory>>> response, Retrofit retrofit) {
 showList(response);
 }
 
 @Override
 public void onFailure(Throwable t) {
 showError(t);
 }
 });
 }

  • 10. You’re doing it right! @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 // Setup initial views
 setContentView(R.layout.activity_main);
 
 // Load data and show it
 Model model = ((MyApplication) getApplicationContext()).getModel();
 model.getTopStories(new Observer() {
 @Override
 public void update(Observable observable, NYTimesResponse<List<NYTimesStory>> data) {
 showList(data);
 }
 });
 }

  • 13. Repository pattern • Repository only has CRUD methods: • Create() • Read() • Update() • Delete() • Model and Repository can be tested separately.
  • 14. Designing for offline Repository… DatastoregetData() Observable<Data>() Network Update? Save
  • 15. Designing for offline • Encapsulate data access • The datastore is single-source-of-truth • Everything is asynchronous • Observer pattern • RxJava • EventBus • Testing becomes easier
  • 17. File system • Define hierarchy using folders • No help from the framework • Use cases: Images, JSON blobs
  • 18. File system // App internal files
 context.getFilesDir();
 context.getCacheDir();
 
 // App external files
 context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
 context.getExternalCacheDir();
 
 // SD Card
 Environment.getExternalStorageDirectory();

  • 19. SharedPreferences • Key-value store • Simple XML file • Use cases: Settings, Key/Value data • Simple API’s and easy to use
  • 20. SharedPreferences // Save data
 SharedPreferences pref = getPreferences(MODE_PRIVATE);
 SharedPreferences.Editor editor = pref.edit();
 editor.putBoolean("key", true);
 editor.commit();
 // Read data boolean data = pref.getBoolean("key", false);

  • 21. Databases • Use cases: Structured data sets • Advanced composing and query capabilities • Complex API’s
  • 22. SQLite vs. the World • SQLite (Relational) • Realm (Object store) • Firebase (Document oriented) • Couchbase Lite (Document oriented) • Parse (Document oriented)
  • 30. SELECT owner.name, dog.name, city.name 
 FROM owner
 INNER JOIN dog ON owner.dog_id = dog.id
 INNER JOIN city ON owner.city_id = city.id
 WHERE owner.name = 'Frank' SQLite
  • 31. String query = "SELECT " + Owner.NAME + ", " + Dog.NAME + ", " + City.NAME 
 + " FROM " + Owner.TABLE_NAME
 + " INNER JOIN " + Dog.TABLE_NAME + " ON " + Owner.DOG_ID + " = " + Dog.ID
 + " INNER JOIN " + City.TABLE_NAME + " ON " + Owner.CITY_ID + " = " + City.ID
 + " WHERE " + Owner.NAME = "'" + escape(queryName) + "'";
 SQLite
  • 32.
  • 33. “Lets use an ORM” Abstract the problem away
  • 34. –Joel Spolsky “All non-trivial abstractions, to some degree, are leaky.”
  • 35. Solved problem? • ActiveRecord • Androrm • Blurb • Cupboard • DBFlow • DBQuery • DBTools • EasyliteOrm • GreenDAO • Ollie • Orman • OrmLite • Persistence • RushORM • Shillelagh • Sprinkles • SquiDB • SugarORM
  • 38. x z y x y z SELECT table1.x, table2.y, table3.z
 FROM table1
 INNER JOIN table2 ON table1.table2_id = table1.id
 INNER JOIN table3 ON table1.table3_id = table3.id
 References in SQL
  • 39. A B C D E F G Realm.getA().getC().getF() Object Store references
  • 40. Zero-copy  Person  {   • name  =  Tommy   • age  =  8   • dog  =  {   • name  =  Lassie          }    }  Person  {   • name  =  Tommy   • age  =  8   • dog  =  {   • name  =  Lassie          }    }  Person  {   • name  =  Tommy   • age  =  8   • dog  =  {   • name  =  Lassie          }    }  PersonProxy  {   • name   • age   • dog      }  PersonProxy  {   • name   • age   • dog      }  Person  {   • name  =  Tommy   • age  =  8   • dog  =  {   • name  =  Lassie          }    } Realm ORM Realm SQLite
  • 41. Benchmarks http://static.realm.io/downloads/java/android-benchmark.zip 1.09% 2.26% 3.79% 4.55% 22.85% 13.37% 1% 1% 1% 1% 1% 1% 0% 5% 10% 15% 20% 25% BatchWrite% SimpleWrite% SimpleQuery% FullScan% Sum% Count% Speedup&vs.&SQLite& Tests&/&1000&objects& Realm% SQLite%
  • 42. SQLite vs. Realm • Part of Android • Relational data model • Based on SQL • Public Domain • One of the most tested pieces of software • Need to map between SQL and Java objects (manually or ORM). • Foreign collections is an unsolvable problem. • Complex API’s • Objects all the way down • Zero copy architecture • Cross-platform • Supports encryption out of the box • Open source* • Custom query language • Will add ~2500 methods + 800 kB of native code. • Still in beta
  • 43. “Talk is cheap. Show me the code.” –Linus Torvalds
  • 44. Adding Realm // ./build.gradle
 buildscript {
 repositories {
 jcenter()
 }
 dependencies {
 classpath 'com.android.tools.build:gradle:2.0.0-alpha1'
 classpath 'io.realm:realm-gradle-plugin:0.86.0'
 }
 }
 // ./app/build.gradle
 apply plugin: 'com.android.application'
 apply plugin: 'realm'

  • 45. Models and Schema public class Person extends RealmObject {
 private String name;
 private int age;
 private Dog dog;
 private RealmList<Cat> cats; // Autogenerated getters/setters
 } public class Cat extends RealmObject {
 private String name;
 // Autogenerated getters/setters
 } public class Dog extends RealmObject {
 private String name;
 // Autogenerated getters/setters
 }
  • 46. Getting an Realm instance // Default configuration. Schema is automatically detected RealmConfiguration config = new RealmConfiguration.Builder(context).build();
 Realm.setDefaultConfiguration(config);
 Realm realm = Realm.getDefaultInstance();
 

  • 47. Create objects - Realm // Create and set persisted objects
 realm.beginTransaction();
 Person person = realm.createObject(Person.class);
 person.setName("Young Person");
 person.setAge(14);
 realm.commitTransaction();
 // Copy java objects
 Person person = new Person();
 person.setName("Young Person");
 person.setAge(14);
 
 realm.beginTransaction();
 realm.copyToRealm(person);
 realm.commitTransaction();
 • Extend RealmObject • POJO: Plain Old Java Object
  • 48. Transactions - Realm // Simple writes
 realm.beginTransaction();
 // ...
 realm.commitTransaction();
 // Automatically handle begin/commit/cancel
 realm.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 // ...
 }
 });

  • 49. Queries RealmResults<Person> results = realm.where(Person.class) .equalTo("age", 99) .findAll();
 RealmResults<Person> results = realm.where(Person.class) .equalTo("cats.name", “Tiger") .findAll();
 RealmResults<Person> results = realm.where(Person.class) .beginsWith("name", “John") .findAllAsync();
 results.addChangeListener(new RealmChangeListener() {
 @Override
 public void onChange() {
 showResults(results);
 }
 });
 • Fluent queries • Semi-typesafe • Easy async • Always up-to-date
  • 50. Network data // Use Retrofit to parse objects
 Retrofit retrofit = new Retrofit.Builder()
 .addConverterFactory(JacksonConverterFactory.create())
 .baseUrl("http://api.nytimes.com/")
 .build();
 
 MyRestApi service = retrofit.create(MyRestApi.class);
 final Data data = service.getData();
 
 // Copy all data into Realm
 realm.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 realm.copyToRealmOrUpdate(data);
 }
 });

  • 51. RxJava (Realm) Observable<Realm> observableRealm = realm.asObservable();
 Observable<RealmResults<Person>> results = realm.where(Person.class) .beginsWith("name", “John") .findAllAsync() .asObservable();
 Observable<Person> results = realm.where(Person.class).findFirst().asObservable();
 Observable<RealmQuery> results = realm.where(Person.class).asObservable();

  • 53. Take aways • Not everyone is on Wifi or 4G networks • Encapsulate data access • Designing for offline gives a a better USER EXPERIENCE!
  • 54. Resources • Repository Pattern: http://martinfowler.com/eaaCatalog/ repository.html • Design for offline: https://plus.google.com/ +AndroidDevelopers/posts/3C4GPowmWLb • MVP example: https://www.code-labs.io/codelabs/ android-testing/#0 • Optimizing network requests: https://www.youtube.com/ playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE • Realm : https://realm.io/docs/java/latest/