SlideShare a Scribd company logo
Persisting data in
SQLite using Room
+Nelson Glauber
@nglauber

www.nglauber.com.br
Room Database
Get DAO
Data Access Objects
Get entities from
database
Persist changes
back to database
Entities
get / set 

field values
Application
apply plugin: 'kotlin-kapt'
...
dependencies {
def room_version = "1.1.0"
implementation "android.arch.persistence.room:runtime:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"
}
Entities
import android.arch.persistence.room.*
@Entity
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = ""
)
import android.arch.persistence.room.*
@Entity(tableName = "tbEvent")
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = ""
)
import android.arch.persistence.room.*
@Entity(indices = [Index("name", unique = true)])
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = ""
)
DAOs
@Dao
interface EventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: Event): Long
@Update
fun update(event: Event): Int
@Delete
fun delete(vararg event: Event): Int
@Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name")
fun eventsByName(name: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :id")
fun eventById(id: Long): Event?
}
@Dao
interface EventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: Event): Long
@Update
fun update(event: Event): Int
@Delete
fun delete(vararg event: Event): Int
@Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name")
fun eventsByName(name: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :id")
fun eventById(id: Long): Event?
}
@Dao
interface EventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: Event): Long
@Update
fun update(event: Event): Int
@Delete
fun delete(vararg event: Event): Int
@Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name")
fun eventsByName(name: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :id")
fun eventById(id: Long): Event?
}
@Dao
interface EventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: Event): Long
@Update
fun update(event: Event): Int
@Delete
fun delete(vararg event: Event): Int
@Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name")
fun eventsByName(name: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :id")
fun eventById(id: Long): Event?
}
@Dao
interface EventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: Event): Long
@Update
fun update(event: Event): Int
@Delete
fun delete(vararg event: Event): Int
@Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name")
fun eventsByName(name: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :id")
fun eventById(id: Long): Event?
}
Database
@Database(entities = [Event::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
}
val db = Room.databaseBuilder(appContext, AppDatabase::class.java, "eventDb")
.build()
val dao = db.eventDao()
val event = Event(0, "Google I/O 2018", "Google's annual conference")
val id = dao.insert(event)
val googleIo = dao.eventById(id)
Log.d("NGVL", "${googleIo.id} ${googleIo.name} - ${googleIo.description}")
val events = dao.eventsByName()
events.forEach {
Log.d("NGVL", "${it.id} ${it.name} - ${it.description}")
}
java.lang.RuntimeException: Unable to start activity ComponentInfo{nglauber.com.br.roomtest/
nglauber.com.br.roomtest.MainActivity}:
java.lang.IllegalStateException: Cannot access database on the main thread since it may
potentially lock the UI for a long period of time.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2830)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it
may potentially lock the UI for a long period of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:251)
at nglauber.com.br.roomtest.EventDao_Impl.insert(EventDao_Impl.java:85)
...
😱😱😱
val db = Room.databaseBuilder(appContext, AppDatabase::class.java, "eventDb")
.allowMainThreadQueries()
.build()
"
Data types
SQLite data types
• INTEGER
• REAL
• TEXT
• BLOB
@Entity(indices = [Index("name", unique = true)])
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = "",
var date: Date = Date()
)
import android.arch.persistence.room.TypeConverter
import java.util.*
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return value?.let { Date(value) }
}
@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
return date?.time ?: 0
}
}
@Database(entities = [Event::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
}
java.lang.RuntimeException: Unable to start activity ComponentInfo{nglauber.com.br.roomtest/
nglauber.com.br.roomtest.MainActivity}:
java.lang.IllegalStateException: Room cannot verify the data integrity.
Looks like you have changed schema but forgot to update the version number.
You can simply fix this by increasing the version number.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2830)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
Migration
object Migration_1_2 : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Event " +
"ADD COLUMN date INTEGER NOT NULL DEFAULT 0")
}
}
val db = Room.databaseBuilder(this.applicationContext,
AppDatabase::class.java,
"eventDb")
.addMigrations(Migration_1_2)
.build()
@Database(entities = [Event::class], version = 2)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
}
val db = Room.databaseBuilder(this.applicationContext,
AppDatabase::class.java,
"eventDb")
.fallbackToDestructiveMigration()
.build()
Relationship
@Entity(indices = [Index("name", unique = true)])
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = "",
var date: Date = Date(),
@Embedded
var location: Address? = null
)
data class Address (
var street: String? = null,
var state: String? = null,
var city: String? = null
)
Event
id
name
info
date
street
state
city
data class Address (
var street: String? = null,
var state: String? = null,
var city: String? = null
)
@Entity(indices = [Index("name", unique = true)])
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "info")
var description : String = "",
var date: Date = Date(),
@Embedded(prefix = "location_")
var location: Address? = null
)
Event
id
name
info
date
location_street
location_state
location_city
@Entity(foreignKeys = [
ForeignKey(entity = Event::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("eventId"),
onDelete = CASCADE
)
])
data class Topic(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
var name: String = "",
var eventId: Long = 0
)
@Entity(...)
data class Event(
...
@Ignore
var topics: List<Topic>? = null
)
@Dao
interface TopicDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertTopics(topics: List<Topic>)
@Query("SELECT * FROM Topic WHERE eventId = :eventId")
fun topicsByEvent(eventId: Long): List<Topic>
}
@Database(entities = [Event::class, Topic::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
abstract fun topicDao() : TopicDao
}
val tdc = Event(0, "TDC", "The Dev Conf",
location = Address("Rua Casa do Ator, 275", "SP", "São Paulo")
)
val eventId = dao.insert(tdc)
val topicDao = db.topicDao()
topicDao.insertTopics(listOf(
Topic(name = "Android", eventId = eventId),
Topic(name = "Mobile", eventId = eventId)
))
Transactions
@Entity(...)
data class Event(
...
@Ignore
var topics: List<Topic>? = null
)
@Dao
interface EventDao {
...
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertTopics(topics: List<Topic>)
@Transaction
fun insertEventWithTopics(event: Event) {
val id = insert(event)
event.topics.run {
this.forEach {
it.eventId = id
}
insertTopics(this)
}
}
}
dao.insertEventWithTopics(
Event().apply {
name = "TDC"
description = "The Dev Conf"
location =
Address("Rua Casa do Ator, 275", "SP", "São Paulo")
topics = listOf(
Topic(name = "Android"),
Topic(name = "Mobile")
)
}
)
The “issue” with 

Foreign Keys
• When should I load the children records?
• Lazy loading is a good approach? 🤔
Relation
class EventWithTopics {
@Embedded
var event: Event = Event()
@Relation(parentColumn = "id",
entityColumn = "eventId",
entity = Topic::class)
var topics: List<Topic> = emptyList()
}
@Entity(...)
open class Event(
...
@Ignore
open var topics: List<Topic> = emptyList()
)
class EventWithTopics: Event() {
@Relation(parentColumn = "id",
entityColumn = "eventId",
entity = Topic::class)
override var topics: List<Topic> = emptyList()
}
@Dao
interface EventDao {
...
@Query("SELECT * FROM Event ORDER BY name")
fun eventsWithTopics(): List<EventWithTopics>
}
val eventsWithTopics = dao.eventsWithTopics()
eventsWithTopics.forEach { event ->
// Do something with event and topics
}
Room + Live Data
dependencies {
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
...
}
@Dao
interface EventDao {
...
@Query("SELECT * FROM Event ORDER BY name")
fun eventsWithTopics(): LiveData<List<EventWithTopics>>
}
dao.eventsWithTopics().observe(this, Observer { eventListWithTopics ->
// Do something...
})
Room + RXJava
dependencies {
def room_version = "1.1.0"
def rxjava2_version = "2.1.13"
def rx2android_version = "2.0.2"
implementation "android.arch.persistence.room:rxjava2:$room_version"
implementation "io.reactivex.rxjava2:rxjava:$rxjava2_version"
implementation "io.reactivex.rxjava2:rxandroid:$rx2android_version"
}
@Dao
interface EventDao {
…
@Query("SELECT * FROM Event ORDER BY name")
fun eventsWithTopics(): Flowable<List<EventWithTopics>>
}
dao.eventsWithTopics()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { events ->
// Do something
}
A quick recap!
✓ Room uses annotations instead of reflection to abstract the SQL
operations.
✓ Room uses the DAO to deal with Entities to persist data in the Database.
✓ Room verify the SQL statements at compile time and has auto-complete
(in Android Studio 3.2).
✓ Room does not force your entities to extends of a base class.
✓ Supports programmatically migration.
✓ Provides an easy way to deal with transactions and relation between
entities.
✓ Supports Live Data and RXJava2.
Questions?
+Nelson Glauber
@nglauber

www.nglauber.com.br
Thank you!

More Related Content

What's hot

Not your Grandma's XQuery
Not your Grandma's XQueryNot your Grandma's XQuery
Not your Grandma's XQuery
William Candillon
 
Building android apps with kotlin
Building android apps with kotlinBuilding android apps with kotlin
Building android apps with kotlin
Shem Magnezi
 
XQuery Rocks
XQuery RocksXQuery Rocks
XQuery Rocks
William Candillon
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
Shem Magnezi
 
Client-side Rendering with AngularJS
Client-side Rendering with AngularJSClient-side Rendering with AngularJS
Client-side Rendering with AngularJS
David Lapsley
 
20141001 delapsley-oc-openstack-final
20141001 delapsley-oc-openstack-final20141001 delapsley-oc-openstack-final
20141001 delapsley-oc-openstack-final
David Lapsley
 
XQuery in the Cloud
XQuery in the CloudXQuery in the Cloud
XQuery in the Cloud
William Candillon
 
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Vagmi Mudumbai
 
OneRing @ OSCamp 2010
OneRing @ OSCamp 2010OneRing @ OSCamp 2010
OneRing @ OSCamp 2010
Qiangning Hong
 
2015 05 27 JSConf - concurrency and parallelism final
2015 05 27   JSConf - concurrency and parallelism final2015 05 27   JSConf - concurrency and parallelism final
2015 05 27 JSConf - concurrency and parallelism final
Naveed Ihsanullah
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
Pascal Rettig
 
Build Widgets
Build WidgetsBuild Widgets
Build Widgets
scottw
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
jeresig
 
Android Developer Toolbox 2017
Android Developer Toolbox 2017Android Developer Toolbox 2017
Android Developer Toolbox 2017
Shem Magnezi
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
 
Rxjs kyivjs 2015
Rxjs kyivjs 2015Rxjs kyivjs 2015
Rxjs kyivjs 2015
Alexander Mostovenko
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
Chris Neale
 
Rethink Async With RXJS
Rethink Async With RXJSRethink Async With RXJS
Rethink Async With RXJS
Ryan Anklam
 
HTML,CSS Next
HTML,CSS NextHTML,CSS Next
HTML,CSS Next
지수 윤
 
JavaScript APIs - The Web is the Platform - .toster conference, Moscow
JavaScript APIs - The Web is the Platform - .toster conference, MoscowJavaScript APIs - The Web is the Platform - .toster conference, Moscow
JavaScript APIs - The Web is the Platform - .toster conference, Moscow
Robert Nyman
 

What's hot (20)

Not your Grandma's XQuery
Not your Grandma's XQueryNot your Grandma's XQuery
Not your Grandma's XQuery
 
Building android apps with kotlin
Building android apps with kotlinBuilding android apps with kotlin
Building android apps with kotlin
 
XQuery Rocks
XQuery RocksXQuery Rocks
XQuery Rocks
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
Client-side Rendering with AngularJS
Client-side Rendering with AngularJSClient-side Rendering with AngularJS
Client-side Rendering with AngularJS
 
20141001 delapsley-oc-openstack-final
20141001 delapsley-oc-openstack-final20141001 delapsley-oc-openstack-final
20141001 delapsley-oc-openstack-final
 
XQuery in the Cloud
XQuery in the CloudXQuery in the Cloud
XQuery in the Cloud
 
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
 
OneRing @ OSCamp 2010
OneRing @ OSCamp 2010OneRing @ OSCamp 2010
OneRing @ OSCamp 2010
 
2015 05 27 JSConf - concurrency and parallelism final
2015 05 27   JSConf - concurrency and parallelism final2015 05 27   JSConf - concurrency and parallelism final
2015 05 27 JSConf - concurrency and parallelism final
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
 
Build Widgets
Build WidgetsBuild Widgets
Build Widgets
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
 
Android Developer Toolbox 2017
Android Developer Toolbox 2017Android Developer Toolbox 2017
Android Developer Toolbox 2017
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
Rxjs kyivjs 2015
Rxjs kyivjs 2015Rxjs kyivjs 2015
Rxjs kyivjs 2015
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Rethink Async With RXJS
Rethink Async With RXJSRethink Async With RXJS
Rethink Async With RXJS
 
HTML,CSS Next
HTML,CSS NextHTML,CSS Next
HTML,CSS Next
 
JavaScript APIs - The Web is the Platform - .toster conference, Moscow
JavaScript APIs - The Web is the Platform - .toster conference, MoscowJavaScript APIs - The Web is the Platform - .toster conference, Moscow
JavaScript APIs - The Web is the Platform - .toster conference, Moscow
 

Similar to Persisting Data on SQLite using Room

Database handling with room
Database handling with roomDatabase handling with room
Database handling with room
Sergi Martínez
 
mobl
moblmobl
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
Thomas Fuchs
 
OBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .pptOBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .ppt
SaadAsim11
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
tdc-globalcode
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Codemotion
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
Heiko Behrens
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
patforna
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
Nebojša Vukšić
 
Prototype Framework
Prototype FrameworkPrototype Framework
Prototype Framework
Julie Iskander
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Tsuyoshi Yamamoto
 
UIKonf App & Data Driven Design @swift.berlin
UIKonf App & Data Driven Design @swift.berlinUIKonf App & Data Driven Design @swift.berlin
UIKonf App & Data Driven Design @swift.berlin
Maxim Zaks
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
Fabio Collini
 
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp KrennPaintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
JavaDayUA
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats Conf
Iain Hull
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
HamletDRC
 
Requery overview
Requery overviewRequery overview
Requery overview
Sunghyouk Bae
 

Similar to Persisting Data on SQLite using Room (20)

Database handling with room
Database handling with roomDatabase handling with room
Database handling with room
 
mobl
moblmobl
mobl
 
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
 
OBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .pptOBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .ppt
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
 
Prototype Framework
Prototype FrameworkPrototype Framework
Prototype Framework
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
UIKonf App & Data Driven Design @swift.berlin
UIKonf App & Data Driven Design @swift.berlinUIKonf App & Data Driven Design @swift.berlin
UIKonf App & Data Driven Design @swift.berlin
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp KrennPaintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats Conf
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Requery overview
Requery overviewRequery overview
Requery overview
 

More from Nelson Glauber Leal

Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
Nelson Glauber Leal
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
Nelson Glauber Leal
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
Nelson Glauber Leal
 
Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021
Nelson Glauber Leal
 
Jetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on AndroidJetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on Android
Nelson Glauber Leal
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
Nelson Glauber Leal
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
Nelson Glauber Leal
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
Nelson Glauber Leal
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Aplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e JetpackAplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e Jetpack
Nelson Glauber Leal
 
Aplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & JetpackAplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & Jetpack
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
Nelson Glauber Leal
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
Nelson Glauber Leal
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
Nelson Glauber Leal
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
Nelson Glauber Leal
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
Nelson Glauber Leal
 
The world of Android Animations
The world of Android AnimationsThe world of Android Animations
The world of Android Animations
Nelson Glauber Leal
 
Android Constraint Layout
Android Constraint LayoutAndroid Constraint Layout
Android Constraint Layout
Nelson Glauber Leal
 
Dominando o Data Binding no Android
Dominando o Data Binding no AndroidDominando o Data Binding no Android
Dominando o Data Binding no Android
Nelson Glauber Leal
 

More from Nelson Glauber Leal (20)

Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
 
Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021
 
Jetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on AndroidJetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on Android
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
Aplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e JetpackAplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e Jetpack
 
Aplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & JetpackAplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & Jetpack
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
 
The world of Android Animations
The world of Android AnimationsThe world of Android Animations
The world of Android Animations
 
Android Constraint Layout
Android Constraint LayoutAndroid Constraint Layout
Android Constraint Layout
 
Dominando o Data Binding no Android
Dominando o Data Binding no AndroidDominando o Data Binding no Android
Dominando o Data Binding no Android
 

Persisting Data on SQLite using Room

  • 1. Persisting data in SQLite using Room +Nelson Glauber @nglauber
 www.nglauber.com.br
  • 2. Room Database Get DAO Data Access Objects Get entities from database Persist changes back to database Entities get / set 
 field values Application
  • 3. apply plugin: 'kotlin-kapt' ... dependencies { def room_version = "1.1.0" implementation "android.arch.persistence.room:runtime:$room_version" kapt "android.arch.persistence.room:compiler:$room_version" }
  • 5. import android.arch.persistence.room.* @Entity data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "" )
  • 6. import android.arch.persistence.room.* @Entity(tableName = "tbEvent") data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "" )
  • 7. import android.arch.persistence.room.* @Entity(indices = [Index("name", unique = true)]) data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "" )
  • 9. @Dao interface EventDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(event: Event): Long @Update fun update(event: Event): Int @Delete fun delete(vararg event: Event): Int @Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name") fun eventsByName(name: String = "%"): List<Event> @Query("SELECT * FROM Event WHERE id = :id") fun eventById(id: Long): Event? }
  • 10. @Dao interface EventDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(event: Event): Long @Update fun update(event: Event): Int @Delete fun delete(vararg event: Event): Int @Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name") fun eventsByName(name: String = "%"): List<Event> @Query("SELECT * FROM Event WHERE id = :id") fun eventById(id: Long): Event? }
  • 11. @Dao interface EventDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(event: Event): Long @Update fun update(event: Event): Int @Delete fun delete(vararg event: Event): Int @Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name") fun eventsByName(name: String = "%"): List<Event> @Query("SELECT * FROM Event WHERE id = :id") fun eventById(id: Long): Event? }
  • 12. @Dao interface EventDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(event: Event): Long @Update fun update(event: Event): Int @Delete fun delete(vararg event: Event): Int @Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name") fun eventsByName(name: String = "%"): List<Event> @Query("SELECT * FROM Event WHERE id = :id") fun eventById(id: Long): Event? }
  • 13. @Dao interface EventDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(event: Event): Long @Update fun update(event: Event): Int @Delete fun delete(vararg event: Event): Int @Query("SELECT * FROM Event WHERE name LIKE :name ORDER BY name") fun eventsByName(name: String = "%"): List<Event> @Query("SELECT * FROM Event WHERE id = :id") fun eventById(id: Long): Event? }
  • 15. @Database(entities = [Event::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun eventDao() : EventDao }
  • 16. val db = Room.databaseBuilder(appContext, AppDatabase::class.java, "eventDb") .build() val dao = db.eventDao() val event = Event(0, "Google I/O 2018", "Google's annual conference") val id = dao.insert(event) val googleIo = dao.eventById(id) Log.d("NGVL", "${googleIo.id} ${googleIo.name} - ${googleIo.description}") val events = dao.eventsByName() events.forEach { Log.d("NGVL", "${it.id} ${it.name} - ${it.description}") }
  • 17. java.lang.RuntimeException: Unable to start activity ComponentInfo{nglauber.com.br.roomtest/ nglauber.com.br.roomtest.MainActivity}: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2830) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6592) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769) Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204) at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:251) at nglauber.com.br.roomtest.EventDao_Impl.insert(EventDao_Impl.java:85) ... 😱😱😱
  • 18. val db = Room.databaseBuilder(appContext, AppDatabase::class.java, "eventDb") .allowMainThreadQueries() .build() "
  • 20. SQLite data types • INTEGER • REAL • TEXT • BLOB
  • 21. @Entity(indices = [Index("name", unique = true)]) data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "", var date: Date = Date() )
  • 22. import android.arch.persistence.room.TypeConverter import java.util.* class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(value) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time ?: 0 } } @Database(entities = [Event::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun eventDao() : EventDao }
  • 23. java.lang.RuntimeException: Unable to start activity ComponentInfo{nglauber.com.br.roomtest/ nglauber.com.br.roomtest.MainActivity}: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you have changed schema but forgot to update the version number. You can simply fix this by increasing the version number. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2830) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6592) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
  • 25. object Migration_1_2 : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE Event " + "ADD COLUMN date INTEGER NOT NULL DEFAULT 0") } } val db = Room.databaseBuilder(this.applicationContext, AppDatabase::class.java, "eventDb") .addMigrations(Migration_1_2) .build() @Database(entities = [Event::class], version = 2) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun eventDao() : EventDao }
  • 26. val db = Room.databaseBuilder(this.applicationContext, AppDatabase::class.java, "eventDb") .fallbackToDestructiveMigration() .build()
  • 28. @Entity(indices = [Index("name", unique = true)]) data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "", var date: Date = Date(), @Embedded var location: Address? = null ) data class Address ( var street: String? = null, var state: String? = null, var city: String? = null ) Event id name info date street state city
  • 29. data class Address ( var street: String? = null, var state: String? = null, var city: String? = null ) @Entity(indices = [Index("name", unique = true)]) data class Event( @PrimaryKey (autoGenerate = true) var id : Long = 0, var name : String = "", @ColumnInfo(name = "info") var description : String = "", var date: Date = Date(), @Embedded(prefix = "location_") var location: Address? = null ) Event id name info date location_street location_state location_city
  • 30. @Entity(foreignKeys = [ ForeignKey(entity = Event::class, parentColumns = arrayOf("id"), childColumns = arrayOf("eventId"), onDelete = CASCADE ) ]) data class Topic( @PrimaryKey(autoGenerate = true) var id: Long = 0, var name: String = "", var eventId: Long = 0 )
  • 31. @Entity(...) data class Event( ... @Ignore var topics: List<Topic>? = null )
  • 32. @Dao interface TopicDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertTopics(topics: List<Topic>) @Query("SELECT * FROM Topic WHERE eventId = :eventId") fun topicsByEvent(eventId: Long): List<Topic> } @Database(entities = [Event::class, Topic::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun eventDao() : EventDao abstract fun topicDao() : TopicDao }
  • 33. val tdc = Event(0, "TDC", "The Dev Conf", location = Address("Rua Casa do Ator, 275", "SP", "São Paulo") ) val eventId = dao.insert(tdc) val topicDao = db.topicDao() topicDao.insertTopics(listOf( Topic(name = "Android", eventId = eventId), Topic(name = "Mobile", eventId = eventId) ))
  • 35. @Entity(...) data class Event( ... @Ignore var topics: List<Topic>? = null )
  • 36. @Dao interface EventDao { ... @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertTopics(topics: List<Topic>) @Transaction fun insertEventWithTopics(event: Event) { val id = insert(event) event.topics.run { this.forEach { it.eventId = id } insertTopics(this) } } }
  • 37. dao.insertEventWithTopics( Event().apply { name = "TDC" description = "The Dev Conf" location = Address("Rua Casa do Ator, 275", "SP", "São Paulo") topics = listOf( Topic(name = "Android"), Topic(name = "Mobile") ) } )
  • 38. The “issue” with 
 Foreign Keys • When should I load the children records? • Lazy loading is a good approach? 🤔
  • 40. class EventWithTopics { @Embedded var event: Event = Event() @Relation(parentColumn = "id", entityColumn = "eventId", entity = Topic::class) var topics: List<Topic> = emptyList() }
  • 41. @Entity(...) open class Event( ... @Ignore open var topics: List<Topic> = emptyList() ) class EventWithTopics: Event() { @Relation(parentColumn = "id", entityColumn = "eventId", entity = Topic::class) override var topics: List<Topic> = emptyList() }
  • 42. @Dao interface EventDao { ... @Query("SELECT * FROM Event ORDER BY name") fun eventsWithTopics(): List<EventWithTopics> } val eventsWithTopics = dao.eventsWithTopics() eventsWithTopics.forEach { event -> // Do something with event and topics }
  • 43. Room + Live Data
  • 44. dependencies { def lifecycle_version = "1.1.1" implementation "android.arch.lifecycle:livedata:$lifecycle_version" ... }
  • 45. @Dao interface EventDao { ... @Query("SELECT * FROM Event ORDER BY name") fun eventsWithTopics(): LiveData<List<EventWithTopics>> } dao.eventsWithTopics().observe(this, Observer { eventListWithTopics -> // Do something... })
  • 47. dependencies { def room_version = "1.1.0" def rxjava2_version = "2.1.13" def rx2android_version = "2.0.2" implementation "android.arch.persistence.room:rxjava2:$room_version" implementation "io.reactivex.rxjava2:rxjava:$rxjava2_version" implementation "io.reactivex.rxjava2:rxandroid:$rx2android_version" }
  • 48. @Dao interface EventDao { … @Query("SELECT * FROM Event ORDER BY name") fun eventsWithTopics(): Flowable<List<EventWithTopics>> } dao.eventsWithTopics() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { events -> // Do something }
  • 49. A quick recap! ✓ Room uses annotations instead of reflection to abstract the SQL operations. ✓ Room uses the DAO to deal with Entities to persist data in the Database. ✓ Room verify the SQL statements at compile time and has auto-complete (in Android Studio 3.2). ✓ Room does not force your entities to extends of a base class. ✓ Supports programmatically migration. ✓ Provides an easy way to deal with transactions and relation between entities. ✓ Supports Live Data and RXJava2.