SlideShare a Scribd company logo
1 of 49
Download to read offline
Persistência de Dados
no SQLite com Room
+Nelson Glauber
@nglauber

www.nglauber.com.br
• Solução padrão existente desde a
primeira versão do Android
• Instruções SQL
• Dados organizados em tabelas
• Chave primária e estrangeira
• Índices
• Views
• Triggers
Tipos de dados no SQLite
• INTEGER
• REAL
• TEXT
• BLOB
SQLiteOpenHelper
class MeuHelper(ctx: Context) :
SQLiteOpenHelper(ctx, "meuBanco", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("create table carro ("+
"_id integer primary key autoincrement, "+
"nome text not null, placa text not null, "+
"ano text not null)")
}
override fun onUpgrade(db: SQLiteDatabase,
oldVersion: Int, newVersion: Int) {
}
}
Inserindo um registro
val helper = MeuHelper(context)
val db = helper.writableDatabase
val values = ContentValues()
values.put("nome", "Fusca")
values.put("placa", "FUS0001")
values.put("ano", 2012)
db.insert("carro", null, values)
db.close()
Atualizando um registro
val db = helper.writableDatabase
val values = ContentValues()
values.put("nome", "Celta")
values.put("placa", "CEL1001")
values.put("ano", 2010)
db.update("carro", values,
"_id = ?", arrayOf("7"))
db.close()
Excluindo um registro
val db = helper.writableDatabase
db.delete("carro", "_id = ?", arrayOf("1"))
db.close()
Uma Query no banco…
val db = helper.readableDatabase
val cursor = db.rawQuery(
"select * from carro where nome like ?",
arrayOf("Ce%"))
while (cursor.moveToNext()) {
val id = cursor.getLong(0)
val nome = cursor.getString(1)
val placa = cursor.getString(
cursor.getColumnIndex("placa"))
Log.d("NGVL", "${id}/${nome} ${placa}")
}
cursor.close()
db.close()
Poderia pra ser mais
simples?
Um ORM talvez… 🤔
ORMs Populares
https://github.com/pardom/ollie
https://github.com/pardom/ActiveAndroid
http://greenrobot.org/greendao/
ORMs Populares
http://ormlite.com/sqlite_java_android_orm.shtml
https://github.com/Raizlabs/DBFlow
Era uma vez em 2015…
Framework Fireside Chat 

(Android Dev Summit 2015)
youtu.be/-VNfWh5UkfY?t=44m2s
😡
No Google I/O 2017…
Architecture Components -
Persistence and Offline
(Google I/O '17)

youtu.be/MfHsPGQ6bgE?
t=2m26s
Levanta a mão agora quem
quer um ORM para Android!
Antes de falar sobre o Room…
vamos falar sobre como
deveria ser um ORM ideal? 🤔
Antes do I/O17…
Talk com Ubiratan Soares
youtu.be/kSmysslUoG8?
t=58m37s
–Ubiratan Soares
“Qual o ORM que eu mais gosto? 

Nenhum! Todos são ruins!”
Um ORM deve…
• Usar anotações (não usar reflection)
• Usar abordagem de DAO para salvar dados
• Ter query builder, validar e auto-completar o SQL
• Não deve me forçar a herdar de base class
• Suporte a RX para acesso assíncrono
• Suporte a migração ser programático e não baseado em
convenções
Room API
buildscript {
ext.roomVersion = '1.0.0-alpha4'
...
}
allprojects {
repositories {
maven { url 'https://maven.google.com' }
mavenCentral()
// google() no Android 3.0
jcenter()
}
}
Dependências
Dependências
dependencies {
...
implementation
"android.arch.persistence.room:runtime:$roomVersion"
kapt
"android.arch.persistence.room:compiler:$roomVersion"
androidTestImplementation
"android.arch.persistence.room:testing:roomVersion"
}
import android.arch.persistence.room.*
@Entity(indices = arrayOf(Index("descr")))
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "descr")
var description : String = ""
)
Entity
@Entity
• Podemos definir o nome da tabela usando a propriedade
tableName
• Podemos definir uma chave primária composta usando a
propriedade primaryKeys e passar a lista dos campos
DAO
import android.arch.persistence.room.*
@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 descr LIKE :arg0 ORDER BY descr")
fun eventsByDescription(description: String = "%"): List<Event>
@Query("SELECT * FROM Event WHERE id = :arg0")
fun eventById(id: Long): Event
}
Regras gerais do DAO
• O Insert/Delete/Update pode receber 1 ou vários objetos
• A Query pode retornar 1 ou vários objetos
• O conjunto de colunas retornadas deve ser igual às
propriedades do objeto a ser retornado
Database
import android.arch.persistence.room.Database
import android.arch.persistence.room.RoomDatabase
@Database(entities = arrayOf(Event::class), version = 1)
abstract class MyRoomDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
}
val db = Room.databaseBuilder(applicationContext,
MyRoomDatabase::class.java, "myDb")
.build()
val dao = db.eventDao()
val event = Event(0, "TDC-SP", "The Developers Conference São Paulo")
val id = dao.insert(event)
val event2 = dao.eventById(id)
Log.d("NGVL", "${event2.id} ${event2.name} - ${event2.description}")
val events = dao.eventsByDescription()
events.forEach {
Log.d("NGVL", "${it.id} ${it.name} - ${it.description}")
}
Tipos de dados
incompatíveis
@Entity(indices = arrayOf(Index("descr")))
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "descr")
var description : String = "",
var date: Date = Date()
)
Type Converter
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 = arrayOf(Event::class), version = 1)
@TypeConverters(Converters::class)
abstract class MyRoomDatabase : RoomDatabase() {
abstract fun eventDao() : EventDao
}
Embedded
@Entity(indices = arrayOf(Index("descr")))
data class Event(
@PrimaryKey (autoGenerate = true)
var id : Long = 0,
var name : String = "",
@ColumnInfo(name = "descr")
var description : String = "",
var date: Date? = null,
@Embedded
var location: Address? = null
)
data class Address {
var street: String? = null
var state: String? = null
var city: String? = null
}
Foreign Keys
import android.arch.persistence.room.*
import android.arch.persistence.room.ForeignKey.CASCADE
@Entity(foreignKeys = arrayOf(
ForeignKey(entity = Event::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("eventId"),
onDelete = CASCADE)))
data class Track(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
var name: String = "",
var eventId: Long = 0
)
O “problema" das 

Foreign Keys
• Eu devo carregar os registros filhos?
• Quando os registros filhos devem ser carregados?
• Lazy loading é a melhor abordagem?
Foreign Keys
@Dao
interface TrackDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertTracks(vararg tracks: Track)
@Query("SELECT * FROM Track WHERE eventId = :arg0")
fun tracksByEvent(eventId: Long): List<Track>
}
@Entity(indices = arrayOf(Index("descr")))
data class Event(
...
@Ignore
var tracks: List<Track>? = null
)
val event = eventDao.eventById(id)
event.tracks = trackDao.tracksByEvent(id)
Smart Join
@Dao
interface EventDao {
...
@Query("SELECT E.*, (SELECT COUNT(*) FROM Track T WHERE T.eventId = E.id)" +
" as numTracks FROM Event E")
fun eventsWithTrackCount(): List<EventWithTrack>
}
class EventWithTrack : Event() {
var numTracks : Int = 0
}
@Entity(...)
open class Event(...)
Migrations
@Entity(indices = arrayOf(Index("descr")))
data class Event(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
var name: String = "",
@ColumnInfo(name = "descr")
var description: String = "",
var date: Date? = null,
var capacity: Int = 0,
@Embedded
var location: Address? = null,
@Ignore
var tracks: List<Track>? = null
)
Migrations
object Migration_1_2 : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Event ADD COLUMN capacity INTEGER NULL")
}
}
val db = Room.databaseBuilder(applicationContext,
MyRoomDatabase::class.java, "myDb")
.addMigrations(Migration_1_2)
.build()
Room + RX2
dependencies {
...
implementation "android.arch.persistence.room:rxjava2:+"
implementation "io.reactivex.rxjava2:rxjava:+"
implementation "io.reactivex.rxjava2:rxandroid:+"
}
Room + RX2
@Dao
interface EventDao {
...
@Query("SELECT * FROM Event WHERE descr LIKE :arg0 ORDER BY descr")
fun eventsByDescription(description: String = "%"): Flowable<List<Event>>
@Query("SELECT * FROM Event WHERE id = :arg0")
fun eventById(id: Long): Flowable<Event>
}
Room + RX2
dao.eventsByDescription()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { events ->
events.forEach {
Log.d("NGVL", "${it.id} ${it.name} - ${it.description}")
}
}
Testing
Testing
@RunWith(AndroidJUnit4::class)
class RoomDemoTests {
lateinit var db: MyRoomDatabase
@Before
@Throws(Exception::class)
fun initDb() {
db = Room.inMemoryDatabaseBuilder(
InstrumentationRegistry.getContext(),
MyRoomDatabase::class.java)
//.allowMainThreadQueries() // please don't
.build()
}
Testing
@After
@Throws(Exception::class)
fun closeDb() {
db.close()
}
Conclusão…
✓Usa anotações ao invés de reflection
✓Usa abordagem de DAO para salvar dados
✓Tem que ter query builder, validar 

e auto-complete para o SQL
✓Não te força a herdar de uma base class
✓Suporta RX
✓Suporta migração programática
Parece bom
esse Room! *
* Essa não é necessariamente 

a opinião do Bira 🙃
Referências
• Room Persistence Library 

https://goo.gl/1z53tu
• Architecture Components do Android - Nelson Glauber

https://goo.gl/Wm7rvc
• 7 Steps To Room - Florina Muntenescu

https://goo.gl/jRDXid
• A evolução da persistência de dados (com sqlite) no
android - Rodrigo Castro

https://goo.gl/FCPDTR
Dúvidas?
@nglauber
+NelsonGlauber
www.nglauber.com.br

More Related Content

What's hot

Introdução ao jquery
Introdução ao jqueryIntrodução ao jquery
Introdução ao jquery
Yuri Costa
 

What's hot (20)

Desvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor AndroidDesvendando as ferramentas e serviços para o desenvolvedor Android
Desvendando as ferramentas e serviços para o desenvolvedor Android
 
JavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersJavaScript e JQuery para Webdesigners
JavaScript e JQuery para Webdesigners
 
jQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê FajolijQuery na Prática - Cauê Fajoli
jQuery na Prática - Cauê Fajoli
 
Javascript para CSharpers - Append B - jQuery
Javascript para CSharpers - Append B - jQueryJavascript para CSharpers - Append B - jQuery
Javascript para CSharpers - Append B - jQuery
 
Introdução ao jquery
Introdução ao jqueryIntrodução ao jquery
Introdução ao jquery
 
Jquery a technical overview
Jquery a technical overviewJquery a technical overview
Jquery a technical overview
 
Introdução ao MongoDB
Introdução ao MongoDBIntrodução ao MongoDB
Introdução ao MongoDB
 
Palestra2009
Palestra2009Palestra2009
Palestra2009
 
JQuery
JQuery JQuery
JQuery
 
Introdução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slidesIntrodução ao MongoDB em 30 slides
Introdução ao MongoDB em 30 slides
 
jQuery Simplificando o JavaScript
jQuery Simplificando o JavaScriptjQuery Simplificando o JavaScript
jQuery Simplificando o JavaScript
 
Grails
GrailsGrails
Grails
 
Apostila de ext js com php e postgresql v1.1
Apostila de ext js com php e postgresql v1.1Apostila de ext js com php e postgresql v1.1
Apostila de ext js com php e postgresql v1.1
 
LaravelSP - MySQL 5.7: introdução ao JSON Data Type
LaravelSP - MySQL 5.7: introdução ao JSON Data TypeLaravelSP - MySQL 5.7: introdução ao JSON Data Type
LaravelSP - MySQL 5.7: introdução ao JSON Data Type
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
 
Apostila de ext js com php e postgresql v1.2
Apostila de ext js com php e postgresql v1.2Apostila de ext js com php e postgresql v1.2
Apostila de ext js com php e postgresql v1.2
 
Mongodb workshop cinlug
Mongodb workshop cinlugMongodb workshop cinlug
Mongodb workshop cinlug
 
Apostila de ext js com php e postgresql v1.3
Apostila de ext js com php e postgresql v1.3Apostila de ext js com php e postgresql v1.3
Apostila de ext js com php e postgresql v1.3
 
Desenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchDesenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-Touch
 
PHP ao Extremo
PHP ao ExtremoPHP ao Extremo
PHP ao Extremo
 

Similar to Persistência de Dados no SQLite com Room

Windows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows AzureWindows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows Azure
Vitor Ciaramella
 
MongoDB - Wagner Bonfiglio - Navegg
MongoDB - Wagner Bonfiglio - NaveggMongoDB - Wagner Bonfiglio - Navegg
MongoDB - Wagner Bonfiglio - Navegg
Felipe Guimarães
 

Similar to Persistência de Dados no SQLite com Room (20)

Windows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows AzureWindows Azure 5/8 - Recursos adicionais do Windows Azure
Windows Azure 5/8 - Recursos adicionais do Windows Azure
 
MongoDB - Wagner Bonfiglio - Navegg
MongoDB - Wagner Bonfiglio - NaveggMongoDB - Wagner Bonfiglio - Navegg
MongoDB - Wagner Bonfiglio - Navegg
 
MongoDB - Workshop Buscapé
MongoDB - Workshop BuscapéMongoDB - Workshop Buscapé
MongoDB - Workshop Buscapé
 
Passagem de Objetos entre Java e Oracle
Passagem de Objetos entre Java e OraclePassagem de Objetos entre Java e Oracle
Passagem de Objetos entre Java e Oracle
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 
Minicurso de PHP Com Ajax
Minicurso de PHP Com AjaxMinicurso de PHP Com Ajax
Minicurso de PHP Com Ajax
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 
jQuery - Visão Geral
jQuery - Visão GeraljQuery - Visão Geral
jQuery - Visão Geral
 
JQuery Alagoinhas Dev Day - UNEB
JQuery Alagoinhas Dev Day - UNEBJQuery Alagoinhas Dev Day - UNEB
JQuery Alagoinhas Dev Day - UNEB
 
TDC2016SP - Trilha BigData
TDC2016SP - Trilha BigDataTDC2016SP - Trilha BigData
TDC2016SP - Trilha BigData
 
Dinamizando Sites Estáticos
Dinamizando Sites EstáticosDinamizando Sites Estáticos
Dinamizando Sites Estáticos
 
Tornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JSTornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JS
 
Minicurso de jQuery
Minicurso de jQueryMinicurso de jQuery
Minicurso de jQuery
 
MongoDB: um banco de dados orientado a documento
MongoDB: um banco de dados orientado a documentoMongoDB: um banco de dados orientado a documento
MongoDB: um banco de dados orientado a documento
 
.Net Community Summit 2018 - Aplicações .NET inteligentes com escala horizont...
.Net Community Summit 2018 - Aplicações .NET inteligentes com escala horizont....Net Community Summit 2018 - Aplicações .NET inteligentes com escala horizont...
.Net Community Summit 2018 - Aplicações .NET inteligentes com escala horizont...
 
One Language to Rule Them All: TypeScript
One Language to Rule Them All: TypeScriptOne Language to Rule Them All: TypeScript
One Language to Rule Them All: TypeScript
 
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...Elasticidade e engenharia de banco de dados para alta performance  - Rubens G...
Elasticidade e engenharia de banco de dados para alta performance - Rubens G...
 
Testes em Aplicações Web com Cactus
Testes em Aplicações Web com CactusTestes em Aplicações Web com Cactus
Testes em Aplicações Web com Cactus
 
Como conectar programas em linguagem java a bases de dados
Como conectar programas em linguagem java  a bases de dadosComo conectar programas em linguagem java  a bases de dados
Como conectar programas em linguagem java a bases de dados
 
DDD > Experiências
DDD > ExperiênciasDDD > Experiências
DDD > Experiências
 

More from 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
 
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
 
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
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
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
 
Introdução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinIntrodução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com Kotlin
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com 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
 

Persistência de Dados no SQLite com Room